I have the following question for this post . In my version, I have the following that I want to make asynchronous. Here is what I have:
public virtual Task<bool> ExecuteAsync() { var tcs = new TaskCompletionSource<bool>(); string exe = Spec.GetExecutablePath(); string args = string.Format("--input1={0} --input2={1}", Input1, Input2); try { var process = new Process { EnableRaisingEvents = true, StartInfo = { UseShellExecute = false, FileName = exe, Arguments = args, RedirectStandardOutput = true, RedirectStandardError = true, WorkingDir = CaseDir } }; process.Exited += (sender, arguments) => { if (process.ExitCode != 0) { string errorMessage = process.StandardError.ReadToEndAsync(); tcs.SetResult(false); tcs.SetException(new InvalidOperationException("The process did not exit correctly. Error message: " + errorMessage)); } else { File.WriteAllText(LogFile, process.StandardOutput.ReadToEnd()); tcs.SetResult(true); } process.Dispose(); }; process.Start(); } catch (Exception e) { Logger.InfoOutputWindow(e.Message); tcs.SetResult(false); return tcs.Task; } return tcs.Task; } }
Here Spec, Input1, Input2, CaseDir, LogFile are all members of the class that ExecuteAsync is a method. Is it normal to use them like that? The parts I'm struggling with are the following:
- I cannot use the async keyword when defining a method (
public virtual async Task<bool> ExecuteAsync() ) without warning that I need the await keyword, while I have one in the lambda expression for the process. Do I even need the async keyword when defining a method? I saw supposedly asynchronous examples where they do not use it, for example. this one . If I take it out, it compiles, but can I use it asynchronously? - Is using the async keyword in a lambda expression and the corresponding
await process.StandardError.ReadToEndAsync() OK inside the process lambda expression? In this example, they do not use async await on the corresponding line, so I wonder how they got away from it? Did this leave it blocking since I was told that the ReadToEnd method ReadToEnd blocking? - Does my call to
File.WriteAllText(LogFile, process.StandardOutput.ReadToEnd()) allow the whole method to be locked? If so, how can I avoid this, if at all possible? - Does exception handling make sense? Should I be aware of any information about the logger method
Logger.InfoOutputWindow that I used in the catch ? - Finally, why does the
process.Exited event always appear before process.Start() in all the examples I came across? Is it possible to put process.Start() before the process.Exited event?
Appreciate any ideas and in advance for your attention and attention.
EDIT. # one:
For # 3 above, I had an idea based in part on a comment from @ René Vogt below, so I made a change to move the call to File.WriteAllText(...) inside the else {} block of the process.Exited event. Perhaps these are addresses number 3.
EDIT # 2:
I made the initial list of changes (now the code snippet has been changed), basically deleted both the async in the function definition and the await keyword in the process.Exited event handler based on the original comments from @ René Vogt, I have not tried my last changes below . When I run, I get an exception:
A plugin has triggered error: System.InvalidOperationException; An attempt was made to transition a task to a final state when it had already completed.
The application log has a call stack as follows:
UNHANDLED EXCEPTION: Exception Type: CLR Exception (v4) Exception Details: No message (.net exception object not captured) Exception Handler: Unhandled exception filter Exception Thread: Unnamed thread (id 29560) Report Number: 0 Report ID: {d80f5824-ab11-4626-930a-7bb57ab22a87} Native stack: KERNELBASE.dll+0x1A06D RaiseException+0x3D clr.dll+0x155294 clr.dll+0x15508E <unknown/managed> (0x000007FE99B92E24) <unknown/managed> (0x000000001AC86B00) Managed stack: at System.Threading.Tasks.TaskCompletionSource`1.SetException(Exception exception) at <namespace>.<MyClass>.<>c__DisplayClass3.<ExecuteAsync>b__2(Object sender, EventArgs arguments) at System.Diagnostics.Process.RaiseOnExited() at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading._ThreadPoolWaitOrTimerCallback.PerformWaitOrTimerCallback(Object state, Boolean timedOut)