前几天我问过this question,但我既没有答案,也没有让它成功。因此,我试图将其缩小,因为问题中存在很多噪音。
事情是,如果我在web api中公开了一个运行cmd.exe的方法,那么如果我不按每次请求调用它两次就可以正常工作。
我的意思是,这段代码运行良好:
data[0] -> PPG
data[1] -> bonds (AMT, current US$)
但是,如果我取消注释评论的行(显然注释掉public class FilesController : ApiController
{
private readonly IRunner _runner;
public FilesController(IRunner runner)
{
_runner = runner;
}
public string Get()
{
return _runner.GetFiles();
}
}
public class Runner : IRunner
{
public Runner()
{
//var cd = @"cd C:\DummyFolder";
//RunCmdPromptCommand(cd);
}
public string GetFiles()
{
var dir = @"cd C:\DummyFolder & dir";
//var dir = "dir";
return RunCmdPromptCommand(dir);
}
private string RunCmdPromptCommand(string command)
{
var process = new Process
{
StartInfo =
{
UseShellExecute = false,
CreateNoWindow = true,
WindowStyle = ProcessWindowStyle.Hidden,
RedirectStandardError = true,
RedirectStandardOutput = true,
FileName = @"cmd.exe",
Arguments = string.Format("/C {0}", command)
}
};
process.Start();
var error = process.StandardError.ReadToEnd();
if (!string.IsNullOrEmpty(error))
{
throw new Exception(error);
}
var output = process.StandardOutput.ReadToEnd();
process.WaitForExit();
return output;
}
}
的第一行,当代码第二次到达时(即使用“dir”)GetFiles
它会卡在它尝试读取标准错误的行。
我不知道为什么,而且我不知道如何在可能发生的情况下强制退出(可能是其他可能发生的情况)
谢谢,
答案 0 :(得分:5)
这是因为:
process.StandardOutput.ReadToEnd();
是同步操作。
摘自MSDN:
可以同步读取重定向的StandardError流 异步。执行Read,ReadLine和 ReadToEnd 等方法 对进程的错误输出流执行同步读取操作。 这些同步读取操作在关联之前不会完成 进程写入其StandardError流,或关闭流。
换句话说,只要进程没有写任何标准错误或关闭流,它就会永远卡在那里。
要解决此问题,建议您使用Async BeginErrorReadLine。摘自MSDN:
相反, BeginErrorReadLine 启动异步读取操作 StandardError流。此方法启用指定事件 流输出的处理程序并立即返回给调用者, 可以在将流输出定向到事件处理程序时执行其他工作。
我认为这将适合您的需要。
使用它。 MSDN中给出的示例非常简单。特别查看这些内容:
netProcess.ErrorDataReceived += new DataReceivedEventHandler(NetErrorDataHandler); //note this event handler add
if (errorRedirect) //in your case, it is not needed
{
// Start the asynchronous read of the standard
// error stream.
netProcess.BeginErrorReadLine(); //note this
}
以及如何定义事件处理程序:
private static void NetErrorDataHandler(object sendingProcess,
DataReceivedEventArgs errLine)
{
// Write the error text to the file if there is something
// to write and an error file has been specified.
if (!String.IsNullOrEmpty(errLine.Data))
{
if (!errorsWritten)
{
if (streamError == null)
{
// Open the file.
try
{
streamError = new StreamWriter(netErrorFile, true);
}
catch (Exception e)
{
Console.WriteLine("Could not open error file!");
Console.WriteLine(e.Message.ToString());
}
}
if (streamError != null)
{
// Write a header to the file if this is the first
// call to the error output handler.
streamError.WriteLine();
streamError.WriteLine(DateTime.Now.ToString());
streamError.WriteLine("Net View error output:");
}
errorsWritten = true;
}
if (streamError != null)
{
// Write redirected errors to the file.
streamError.WriteLine(errLine.Data);
streamError.Flush();
}
}
}