Chapter 9. Exceptions in Async Code

In synchronous code, exceptions work their way up the call stack, back through each method call until they reach either a try and catch that can catch them, or they leave your code. In async code, particularly after a method has been resumed after an await, the current call stack has very little to do with the programmer’s intention, and mostly contains framework logic to resume the async method. The exception would be impossible to catch in your calling code, and stack traces wouldn’t be very helpful at all, so C# changes the behavior of exceptions to be more useful.

Note

You can still see the raw call stack in a debugger.

Exceptions in Async Task-Returning Methods

Most async methods you write will return Task or Task<T>. Chains of these methods, each awaiting the next, are the asynchronous version of the call stack we’re familiar with in synchronous code. C# strives to make the behavior of exceptions in these methods feel very similar to working with synchronous methods. In particular, try..catch blocks placed around an awaited async method will catch exceptions thrown inside that async method.

async Task Catcher()
{
    try
    {
        await Thrower();
    }
    catch (AlexsException)
    {
        // Execution will reach here
    }
}

async Task Thrower()
{
    await Task.Delay(100);
    throw new AlexsException();
}

Note

Until execution reaches the first await, the synchronous call stack and the chain of async methods are exactly the same. The behavior of exceptions at that point is still changed ...

Get Async in C# 5.0 now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.