Ответ 1
Один стандартный вопрос: процесс может ждать, пока вы его прочитаете. Создайте отдельный поток, чтобы читать его стандартный вывод, пока вы ждете его выхода. Это немного боль, но это может быть проблемой.
Я написал быстрый и грязный обертку вокруг svn.exe, чтобы получить некоторый контент и что-то сделать с ним, но для некоторых входов он иногда и воспроизводимо зависает и не заканчивается. Например, одним вызовом является список svn:
svn list "http://myserver:84/svn/Documents/Instruments/" --xml --no-auth-cache --username myuser --password mypassword
Эта командная строка отлично работает, когда я просто делаю это из командной оболочки, но она зависает в моем приложении. Мой код С# для запуска:
string cmd = "svn.exe";
string arguments = "list \"http://myserver:84/svn/Documents/Instruments/\" --xml --no-auth-cache --username myuser --password mypassword";
int ms = 5000;
ProcessStartInfo psi = new ProcessStartInfo(cmd);
psi.Arguments = arguments;
psi.RedirectStandardOutput = true;
psi.WindowStyle = ProcessWindowStyle.Normal;
psi.UseShellExecute = false;
Process proc = Process.Start(psi);
StreamReader output = new StreamReader(proc.StandardOutput.BaseStream, Encoding.UTF8);
proc.WaitForExit(ms);
if (proc.HasExited)
{
return output.ReadToEnd();
}
Это занимает 5000 мс и никогда не заканчивается. Продление времени не помогает. В отдельной командной строке он запускается мгновенно, поэтому я уверен, что он не связан с недостаточным временем ожидания. Однако для других входов это работает нормально.
Я также попробовал запустить отдельный cmd.exe здесь (где exe - svn.exe, а args - исходная строка arg), но повесился все еще:
string cmd = "cmd";
string arguments = "/S /C \"" + exe + " " + args + "\"";
Что я могу здесь прикрутить, и как я могу отлаживать этот внешний процесс?
EDIT:
Я только сейчас обойдусь этим. Mucho благодаря Jon Skeet за его предложение, которое действительно отлично работает. У меня есть еще один вопрос о моем методе обработки этого, хотя, поскольку я многопоточный новичок. Я бы хотел предложить предложения по улучшению любых вопиющих недостатков или чего-то иного, кроме глупого. Я закончил создание небольшого класса, который содержит поток stdout, StringBuilder для хранения вывода и флаг, чтобы сообщить, когда он закончит. Затем я использовал ThreadPool.QueueUserWorkItem и передал экземпляр моего класса:
ProcessBufferHandler bufferHandler = new ProcessBufferHandler(proc.StandardOutput.BaseStream,
Encoding.UTF8);
ThreadPool.QueueUserWorkItem(ProcessStream, bufferHandler);
proc.WaitForExit(ms);
if (proc.HasExited)
{
bufferHandler.Stop();
return bufferHandler.ReadToEnd();
}
... и...
private class ProcessBufferHandler
{
public Stream stream;
public StringBuilder sb;
public Encoding encoding;
public State state;
public enum State
{
Running,
Stopped
}
public ProcessBufferHandler(Stream stream, Encoding encoding)
{
this.stream = stream;
this.sb = new StringBuilder();
this.encoding = encoding;
state = State.Running;
}
public void ProcessBuffer()
{
sb.Append(new StreamReader(stream, encoding).ReadToEnd());
}
public string ReadToEnd()
{
return sb.ToString();
}
public void Stop()
{
state = State.Stopped;
}
}
Это похоже на работу, но я сомневаюсь, что это лучший способ. Это разумно? И что я могу сделать, чтобы улучшить его?
Один стандартный вопрос: процесс может ждать, пока вы его прочитаете. Создайте отдельный поток, чтобы читать его стандартный вывод, пока вы ждете его выхода. Это немного боль, но это может быть проблемой.
Джон Скит прямо на деньги!
Если вы не возражаете против опроса после запуска команды svn, попробуйте следующее:
Process command = new Process();
command.EnableRaisingEvents = false;
command.StartInfo.FileName = "svn.exe";
command.StartInfo.Arguments = "your svn arguments here";
command.StartInfo.UseShellExecute = false;
command.StartInfo.RedirectStandardOutput = true;
command.Start();
while (!command.StandardOutput.EndOfStream)
{
Console.WriteLine(command.StandardOutput.ReadLine());
}
Я знаю, что мои SVN-репозиции могут работать медленно, поэтому, возможно, 5 секунд недостаточно долго? Вы скопировали строку, которую вы передаете процессу из точки останова, поэтому вы уверены, что ничего не подсказывает?
Я знаю, что это старый пост, но, возможно, это поможет кому-то. Я использовал это для выполнения некоторых команд CLI AWS (Amazon Web Services) с использованием задач .Net TPL.
Я сделал что-то подобное в моем исполнении команды, которая выполняется в задаче .NET TPL, которая создается в моем методе background рабочего bgwRun_DoWork
для WinForm, который содержит цикл с while(!bgwRun.CancellationPending)
. Это содержит чтение стандартного вывода процесса через новый поток с использованием класса .Net ThreadPool.
private void bgwRun_DoWork(object sender, DoWorkEventArgs e)
{
while (!bgwRun.CancellationPending)
{
//build TPL Tasks
var tasks = new List<Task>();
//work to add tasks here
tasks.Add(new Task(()=>{
//build .Net ProcessInfo, Process and start Process here
ThreadPool.QueueUserWorkItem(state =>
{
while (!process.StandardOutput.EndOfStream)
{
var output = process.StandardOutput.ReadLine();
if (!string.IsNullOrEmpty(output))
{
bgwRun_ProgressChanged(this, new ProgressChangedEventArgs(0, new ExecutionInfo
{
Type = "ExecutionInfo",
Text = output,
Configuration = s3SyncConfiguration
}));
}
if (cancellationToken.GetValueOrDefault().IsCancellationRequested)
{
break;
}
}
});
});//work Task
//loop through and start tasks here and handle completed tasks
} //end while
}
Мне пришлось отказаться от exe на клиентской машине и использовать Process.Start для ее запуска.
Вызывающее приложение будет зависать после вызова, и проблема закончилась тем, что их машина предположила, что exe опасна и не позволяет другим приложениям запускать ее.
Щелкните правой кнопкой мыши exe и перейдите к свойствам. Нажмите "Разблокировать" в нижней части экрана рядом с предупреждением безопасности.