The async/await pattern in C# is syntactic sugar at its most decadent, allowing developers to easily write asynchronous code. However, decadence has limits, and like a too thick layer of butter cream on my post workout cupcake, Task.ConfigureAwait(bool) can leave an unpleasurable mouth feel when used incorrectly.
Naming things is hard, they should be descriptive, tell you something about their owner. So what does
ConfigureAwait tell us? Well, it obviously configures the awaiter of a task to either,
- continue on the same SynchronizationContext as the caller, if
trueis passed; or
- throw caution to the wind and continue execution on whatever thread is available, if
By default tasks are configured to capture the synchronization context and continue on the same thread as the caller. This makes sense when writing GUI applications and you want to modify the UI after getting a result from an asynchronous operation. So then, why is it recommended to
ConfigureAwait(false) when writing libraries? Well, if the consumer of your awesome async library decides to do a synchronous blocking call (e.g.
Task.GetAwaiter().GetResult()) then the code will deadlock as the caller thread is blocked waiting for the task to finish, and the task is waiting to resume on the calling thread.
To avoid this deadlock there are two options,
- Library async methods should use
- Use async/await all the way down (no dirty calls to
Personally I wish that configure await was false by default, requiring developers to opt-in to context capturing. At some point it all starts to sound like a bit of technobable,
“Captain! Neglecting to configure the awaiter could cause a tachyon inversion of the context synchronometer, resulting in a temporal anomaly! Simply put Sir, we’ll be frozen in time!”
“Engineering, set the dilithium crystals to configure await false! Maximum warp! Engage!”
That was quite a bit of preamble to get to the point of this whole thing, ASP.NET and its
SynchronizationContext. For ASP.NET Classic (think .NET Framework), there is a
System.Web.AspNetSynchronizationContext, however, for the new and shiny ASP.NET Core there isn’t one. If you inspect
SynchronizationContext.Current you’ll find that it’s set to
AspNetSynchronizationContext ensured things like
HttpContext.Current, user identity and culture were preserved, but in the dependency injected world of ASP.NET Core there just isn’t a need for it anymore. As an added benefit there is a performance gain when avoiding context capturing. So, for ASP.NET Core applications
ConfigureAwait(false) is not required, however, it should still be used in a library that could be called from an environment where there is a context.
Now, the question that inspired me to add this post into the ether,
If an ASP.NET Core application is running under full framework (e.g. to support Entity Framework 6), do I still need to use