Be careful and smart!
This is mostly for .NET Core and .NET 5+, however can be applied to older versions of the framework.
Intro #
Have you ever wondered if you need to put .ConfigureAwait(false)
on each async call in .NET?
I think you heard that it can help to avoid deadlocks if there is SynchronizationContext
and increase performance.
But do you really like adding .ConfigureAwait(false)
everywhere just in case? Like you get paid for this!
// These are not real-world examples, but make a picture:
var user = await _usersRepository.GetUser(userId).ConfigureAwait(false);
await _emailService.SendEmail(user.Email, message).ConfigureAwait(false);
// or with Polly...
await Policy.Handle<ApiException>()
.WaitAndRetryAsync(5, _ => TimeSpan.FromMilliseconds(500))
.ExecuteAsync(async () =>
await _client.GetAllUsers().ConfigureAwait(false))
.ConfigureAwait(false);
Doesn’t look good, huh? If only we can avoid adding .ConfigureAwait(false)
everywhere, it would become much cleaner.
Remember the less code we write, the less code we need to read and support.
How to decide if we need .ConfigureAwait(false)? #
We won’t get deep into SynchronizationContext
and stuff, you’ll find links to great resources below.
Just brief details and a rule of thumb here 👍
You don’t need .ConfigureAwait(false) #
…when you don’t have SynchronizationContext
. That’s easy!
But how to understand if there is a SynchronizationContext
presented? Check this static field by printing using Console.WriteLine
, Debug.WriteLine
or ILogger
(you can also try to use Debug Watch, but debugger can affect the results especially for test frameworks):
SynchronizationContext.Current
If it’s null
, then there is no SynchronizationContext
and you can avoid adding .ConfigureAwait(false)
to async calls in your code.
In .NET Core and .NET 6 you can avoid adding .ConfigureAwait(false)
in the following execution contexts:
- Console apps
- ASP.NET Core
- SpecFlow, MSTest, NUnit tests
XUnit actually has
one, but in most cases it’s safe to avoid adding .ConfigureAwait(false)
.
Nice, isn’t it?
Another thing is UI native code, where you want to proceed with execution on the main UI thread. But you should know it already if you work with UI! 😉
And don’t worry about performance improvements - they are negligible. You can prove it anytime with BenchmarkDotNet.
You need .ConfigureAwait(false) #
Sometimes you need it though. If you’re writing a library, you don’t know where your code will be executed.
So to avoid possible issues in the caller context, just add .ConfigureAwait(false)
to async-await calls.
Also if you have SynchronizationContext
, but you don’t need to execute continuation on it after await
- add .ConfigureAwait(false)
.
Rule of thumb 👍 #
- Add
.ConfigureAwait(false)
if you write a library or when there isSynchronizationContext
and you don’t want to capture it. - Don’t add it if you don’t have
SynchronizationContext
(Console apps, ASP.NET Core and tests in .NET Core and .NET 6) or want to capture the main UI thread.