Is there any async equivalent of Process.Start?
Process.Start()
only starts the process, it doesn't wait until it finishes, so it doesn't make much sense to make it async
. If you still want to do it, you can do something like await Task.Run(() => Process.Start(fileName))
.
But, if you want to asynchronously wait for the process to finish, you can use the Exited
event together with TaskCompletionSource
:
static Task<int> RunProcessAsync(string fileName)
{
var tcs = new TaskCompletionSource<int>();
var process = new Process
{
StartInfo = { FileName = fileName },
EnableRaisingEvents = true
};
process.Exited += (sender, args) =>
{
tcs.SetResult(process.ExitCode);
process.Dispose();
};
process.Start();
return tcs.Task;
}
Here's my take, based on svick's answer. It adds output redirection, exit code retention, and slightly better error handling (disposing the Process
object even if it could not be started):
public static async Task<int> RunProcessAsync(string fileName, string args)
{
using (var process = new Process
{
StartInfo =
{
FileName = fileName, Arguments = args,
UseShellExecute = false, CreateNoWindow = true,
RedirectStandardOutput = true, RedirectStandardError = true
},
EnableRaisingEvents = true
})
{
return await RunProcessAsync(process).ConfigureAwait(false);
}
}
private static Task<int> RunProcessAsync(Process process)
{
var tcs = new TaskCompletionSource<int>();
process.Exited += (s, ea) => tcs.SetResult(process.ExitCode);
process.OutputDataReceived += (s, ea) => Console.WriteLine(ea.Data);
process.ErrorDataReceived += (s, ea) => Console.WriteLine("ERR: " + ea.Data);
bool started = process.Start();
if (!started)
{
//you may allow for the process to be re-used (started = false)
//but I'm not sure about the guarantees of the Exited event in such a case
throw new InvalidOperationException("Could not start process: " + process);
}
process.BeginOutputReadLine();
process.BeginErrorReadLine();
return tcs.Task;
}