Reputation: 696
It really feels like I'm following best practices according to MSDN. But I'm most likely missing something because my code hangs after continuing from this line: string errorOutput = cmd.StandardError.ReadToEnd();
. What am I doing wrong?
var batchfile = File.OpenWrite("run.bat");
StreamWriter writer = new StreamWriter(batchfile);
writer.Write("dotnet run" + '\n');
//writer.Write("set /p temp=\"Hit enter to continue\"" + '\n');
writer.Close();
var cmd = new Process();
cmd.StartInfo.FileName = batchfile.Name;
cmd.StartInfo.UseShellExecute = false;
cmd.StartInfo.RedirectStandardError = true;
cmd.Start();
string errorOutput = cmd.StandardError.ReadToEnd();
cmd.WaitForExit();
var outputfile = File.OpenWrite("run_errorOut.txt");
StreamWriter outputWriter = new StreamWriter(outputfile);
outputWriter.Write(errorOutput);
outputWriter.Close();
In case it helps: At the moment this code is running inside an xunit test inside a dotnetcore2.2 app (its target framework is 'netcoreapp2.2').
Upvotes: 4
Views: 1897
Reputation: 685
So I had a very similar problem not that long ago, doing almost exactly the same and what I found was that:
cmd.HasExited
is false until the StandardError/Output has been read so that cannot be used to detect when finished (and then read StandardError/Output)The most reliable way I have found to do this is to use the provided events on Process
:
var outData = new StringBuilder();
var errData = new StringBuilder();
cmd.OutputDataReceived += (sender, args) => outData.Append(args.Data ?? string.Empty);
cmd.ErrorDataReceived += (sender, args) => errData.Append(args.Data ?? string.Empty);
And then after cmd.Start() == true
:
cmd.BeginErrorReadLine();
cmd.BeginOutputReadLine();
To start the events firing.
After the process has exited you can call .ToString()
on the StringBuilders to get the data:
Console.WriteLine(outData.ToString());
Console.WriteLine(errData.ToString());
(Note that .ToString()
can be implicit when using Console.WriteLine
)
Upvotes: 8