Exception Handling In Asynchronous Code

It is important to know how exceptions are handled in an asynchronous program. Partly because these subtle points can sometime become a headache. When exception are thrown in a code that runs inside a task, all the exceptions are placed on the task object and returned to the calling thread. When exceptions happen, all the exceptions are re-thrown by the calling thread. To do that they’re wrapped inside AggregateException and returned to the caller. So when we await a task, we only get the first exception from a collection of exceptions that might exist on a task. In this post I’m going to discuss these points and bring to your attention some important aspect of exceptions in async programs.

How Exceptions Handled in Async Program

There’s a difference between how a normal program handle and receive exceptions and how a task-based program does it. When an exception happens in a task based program all the exceptions are place on task object and returned. The important thing is if we need all exceptions we need to retrieve it. In other words if multiple exceptions happen, if we await the task in a normal way, we only going to get the latest exception. Let me clarify what I’ve said with an example.

In the example above, we’re not going to enter the catch (AggregateException e) block. Instead we’re going to enter the catch (Exception e) block and we only going to receive one of the exceptions. Although two exception happened when we run the program. So we only get the NotImplementedException and not the InvalidOperationException.

When using await, it’s going to unwrap the first exception and return it, that’s why we don’t hit the catch (AggregateException e) line. But if we use something like the below code sample, we catch the AggregateException, note that it’s not a good idea since we’re blocking the running thread.

 

Get All Exceptions From A Task

In  the previous example we saw how other exceptions are ignored if we handle exceptions with tasks in a normal way. Now let’s see how we can retrieve all of them if we need to.

In the code above, we catch the exceptions from the Exception property and assign it to a variable of type AggregateException.

Note that this example is not about best practices regarding handling exceptions, but how we can retrieve all the exceptions from a task.

How to Deal With Nested AggregateExceptions

Imagine a scenario when a task contains another task, the inner task throws couple of exceptions. Now the parent task throws exceptions too, in this scenario, the InnerExceptions property of the parent contains another AggregateException. In this case we can use Flatten() method to flatten all the child exceptions.

If you run the above code and examine the nestedExceptions and flatNestedExceptions variables, you’ll see how aggregate exception are flattened.

Treat Exceptions as Handled by AggregateException.Handle

You can use AggregateException.Handle to handle certain exceptions and ignore them if they’re not harmful. The AggregateException.Handle accept a delegate that returns a bool. If what’s returned is true, the exception is considered to be handled. But if it returns false, the exception re-thrown again after Handle ends. Let’s consider this code excerpt for example.

In this case, the exception of type ArgumentNullException re-thrown after the Handle method finish executing.

What Happens to Exceptions When Using Async Void

There’s a lot of reasons why we shouldn’t use async void, but I’m going to show you what happens to exceptions when used this way. Take the below code for instance.

If you run this code, we never hit the line that catches the exception. Because the program cannot re-throw the exception in the calling thread and there’s no task object to place it on. Now let’s correct this program by using Task instead of void. If we run the program now, we see that we hit the lines that catches the exception.

Summary

In this post we saw how exceptions are handled differently when using task based APIs. We also saw some mistakes and gotchas to watch for when we dealing with exceptions in an asynchronous programs.

Share...
 

Hamid Mosalla

Hi, I'm Hamid ("Arman"). I'm a software developer with 8+ years of experience in C#, .NET Core, Software Architecture and Web Development. I enjoy creating dev tools, contributing to open-source projects, and sharing insights on my blog. Outside of tech, I’m into indie cinema, classical music and abstract art.

 

2 thoughts on “Exception Handling In Asynchronous Code

Leave a Reply

Your email address will not be published. Required fields are marked *