Tasks and the AggregateException
When running a task asynchronous in an asynchronous environment, you can catch exceptions as you just using asynchronous code. When an exception occurs, C# will catch any exception and put it into the Task that will be returned to the caller. Furthermore, the Task becomes Faulted. The exception will be thrown now at the place where the await is put to wait for the result of the asynchronous call which caused the exception.
This changes however when calling a asynchronous task in a synchronous way.
Calling asynchronous tasks in a synchronous way
When calling a asynchronous task in a synchronous way, we block the execution of the normal flow until the asynchronous task has completed. In this scenario when an exception occurs in a task, it will wrap the exception(s) within an AggregateException.
The reason for this is that a task can run multiple tasks parallel. In this way the exceptions of the various tasks are put in this AggrageteException. Also when you execute only one task, it will still wrap the exception thrown within the task in an AggregateException. So using Task.Result or Task.Wait will throw an AggregateException.
To prevent wrapping the exceptions in an AggregateException, you use the following mechanism:
Task task = …;
T result = task.GetAwaiter().GetResult();
The last mechanism is actually, in my opinion, the best way to execute a asynchronous call in a synchronous way. Since in this way you don’t have to deal with the AggregateException, but can handle the exception which caused the issue directly.
Asynchronous tasks in an asynchronous environment
Wait and Result also throw AggregateExceptions within an asynchronous environment. So in this case it’s better to use await, so you can catch exceptions as in a normal synchronous environment you would use it. After all the async pattern in C# tries to give the programmer ways to create asynchronous methods as if it is a synchronous method.
The following table gives an overview of which type of exception to expect when:
AggregateException | “Normal” exception |
Task.Result | await …. |
Task.Wait() | Task.GetAwaiter().GetResult() |