The task and the await /async never ceases to amaze me. That because there is so much under covers( see https://channel9.msdn.com/Events/TechDays/Techdays-2014-the-Netherlands/Async-programming-deep-dive )
Let’s say that we have this code that awaits and throws ( or not ) an exception:
static async Task<bool> test(int delaySeconds,Exception throwEx) { Console.WriteLine($"enter {delaySeconds} "); await Task.Delay(delaySeconds * 1000); Console.WriteLine($"finish waiting {delaySeconds} and throw Exception: {throwEx.Message}"); if (throwEx != null) { throw throwEx;//never do this in production } return true; }
First problem: Error order
What this code will produce as output for the line Console.WriteLine(“err ” + ex.GetType().Name); ?
Console.WriteLine("start"); var t10Ex = test(delaySeconds: 10,throwEx: new ArgumentException("problem with argument")); var t19Ex = test(delaySeconds: 19,throwEx: new DllNotFoundException("not found dll")); var t100NotEx = test(delaySeconds: 100,throwEx: null); try { await Task.WhenAll(new Task[] { t19Ex,t10Ex,t100NotEx }); } catch (Exception ex) { Console.WriteLine("err " + ex.GetType().Name); } finally { Console.WriteLine("in finally"); } Console.WriteLine("waiting in main"); await Task.Delay(100 * 1000); Console.WriteLine("finish");
Answer: err DllNotFoundException
. That is because the await it produce error for the first item in the array,not for the first item in chronological order. More,it will wait for all tasks to finish.
Second problem: Grab all errors
How do you modify the above code to grab all errors ?
Answer: By introducing a new variable,tAll . Attention: the exception is the same ( dllNotFound),however,the whole AggregateException is in tAll.Exception
Task tAll=null; try { tAll = Task.WhenAll(new Task[] { t19Ex,t10Ex,t100NotEx }); await tAll; } catch (Exception ex) { Console.WriteLine("err " + ex.GetType().Name); Console.WriteLine(" all exception here:" + tAll.Exception); } finally { Console.WriteLine("in finally"); }
Third problem: Continue With
Let’s modify slightly the code for using ContinueWith. When the “in continue with ” will be displayed ?
Console.WriteLine("start"); var t10Ex = test(delaySeconds: 10,throwEx: new ArgumentException("problem with argument")); var t20NotEx = test(delaySeconds: 20,throwEx: null); var t10ContinueWith = t10Ex.ContinueWith(async (previousTask) => { await Task.Delay(25 * 1000); Console.WriteLine("in continue with " + previousTask.IsCompletedSuccessfully); }).Unwrap(); try { await Task.WhenAll(t10Ex,t20NotEx ); } catch (Exception ex) { Console.WriteLine("err " + ex.GetType().Name); } finally { Console.WriteLine("in finally"); } Console.WriteLine("waiting in main"); await Task.Delay(100 * 1000); Console.WriteLine("finish");
Answer: : AFTER displaying “waiting in main” . Basically,you do not wait for ContinueWith,you wait for the first task in the ContinueWith construct ( t10Ex in our case)
And a question for you : Why do we need Unwrap ? ( Hint: try the code without and see the exception!)
Leave a Reply