Today my colleagues and I discussed how to handle exceptions in C# 5.0 async
methods correctly, and we wondered if awaiting multiple tasks at once also observes
Task.WhenAll
returns a task and like all tasks the Exception
property holds an AggregateException
that combines all exceptions.
When you await
such a task only the first exception will actually be thrown.
... Whether because of child tasks that fault, or because of combinators like Task.WhenAlll, a single task may represent multiple operations, and more than one of those may fault. In such a case, and with the goal of not losing exception information (which can be important for post-mortem debugging), we want to be able to represent multiple exceptions, and thus for the wrapper type we chose AggregateException.
... Given that, and again having the choice of always throwing the first or always throwing an aggregate, for “await” we opt to always throw the first
from Task Exception Handling in .NET 4.5
It's up to you to choose if you want to handle just the first using await task;
(true in most cases) or handle all using task.Exception
(as in my example below), but in both cases a
and b
would not raise an UnobservedTaskException
.
var task = Task.WhenAll(a, b);
try
{
await task;
}
catch
{
Trace.WriteLine(string.Join(", ", task.Exception.Flatten().InnerExceptions.Select(e => e.Message)));
}