Process.WaitForExitAsync is not the async equivalent of Process.WaitForExit in .NET 5
.NET 5 introduces a new very handy method: Process.WaitForExitAsync(CancellationToken)
(documentation). This method waits for the process to exit, or for the cancellationToken to be canceled. It is very similar to the synchronous version Process.WaitForExit
and I'm pretty sure some analyzers will suggest replacing the method with the new asynchronous method.
Both methods behave differently. WaitForExit
ensures that all processing has been completed, including the handling of asynchronous events for redirected standard output. WaitForExitAsync
doesn't wait for redirected output to complete. I reported this issue too lately, so it won't be part of .NET 5 😦
The workaround is to call WaitForExit
after WaitForExitAsync
. This won't be fully asynchronous as waiting for the output will be synchronous, but it will be correct. To demonstrate this behavior, you can run this unit test:
[Fact]
public async Task Repro_WaitForExitAsync()
{
var logs = new List<string>();
var psi = new ProcessStartInfo("cmd", "/C echo test")
{
UseShellExecute = false,
RedirectStandardOutput = true,
};
using var process = new Process();
process.StartInfo = psi;
process.OutputDataReceived += (sender, e) => { if (e.Data != null) logs.Add(e.Data); };
process.Start();
// Give time for the process (cmd) to terminate
await Task.Delay(1000);
process.BeginOutputReadLine();
await process.WaitForExitAsync();
Assert.Empty(logs); // ⚠ The collection is empty, but it should contain 1 item
process.WaitForExit();
Assert.Equal(new[] { "test" }, logs); // ok because WaitForExit waits for redirected streams
}
If you update your code to use asynchronous methods and you redirect the output stream, be careful with this method. You may introduce a very subtle bug.
Do you have a question or a suggestion about this post? Contact me!