Async EventHandlers - A Simple Safety Net to the Rescue

When we discuss async EventHandlers, the first thing that comes to mind for many of us is that it's the only exception that we seem to allow for the dreaded async void setup. When I had written about this before, I was excited that I was exploring a solution that involved actually allowing async void to exist (without wanting to pull the rest of my hair out). For me, this was much more about some clever tricks we can use to overcome async EventHandlers than it was to provide solutions for avoiding the problem entirely.

With that said though, there was a lot of traction on the article, which I am very thankful for, and some folks expressed opinions that they'd rather solve async EventHandlers a different way. I thought this was a great point, so I wanted to come up with an alternative approach that doesn't fix async void, but it allows you to a-void it (see what I did there?) entirely while solving some of the challenges with async EventHandlers.

In this article, I will present another solution that you can try out in your own code. We'll address the pro's and con's from my perspective with respect to how it can be used so you can decide if it makes sense for your use case. You can also find some interactable code on .NET fiddle right over here. Otherwise, you can check the code out on GitHub if you'd like to clone it down locally to try it out.


.NET Async Event Handler Companion Video

Check out this video for companion content on how to work with a C# async event handler:


The Problem We Face With a C# Async Event Handler

The problem we face with async EventHandlers is that the signature for events that we can subscribe to in C# by default looks something like this:

void TheObject_TheEvent(object sender, EventArgs e);

And you'll notice that by having void out the front of this signature, we're forced to use void in our own handlers in order to subscribe to the event. This means that if you want your handler to ever run async/await code, you'll need to await inside your void method... Which introduces the big scary async void pattern that we're told to avoid like the plague.

And why? Because async void breaks the ability for exceptions to bubble up properly and can cause a ton of headaches as a result.

The previous article addressed this by allowing us to get creative on the invocation side of things but...

  • We might need support for this on objects we don't control the invocation of events for (i.e. you are hooking up to a button's click event in your favorite UI framework)
  • Some people see the usage of the context inside of that solution as a hack (I'm not disagreeing with that either).
  • ... Specifically with event handlers we have some other more simple tricks we can do to support async EventHandlers!

In my opinion, simple is better... so if you read my previous article on async void and your goal was really just to deal with EventHandlers, this should help.