See the question and my original answer on StackOverflow

This blocking/lock issue is caused by the code that's generated undercovers by the async/await syntactic sugar. If you don't add ConfigureAwait(false), the compiler generates something that's cool for a UI application (UI is a general term, could be ASP.NET - not core - , WPF, Winforms, etc.), but that can be deadly otherwise.

A lot has beew written on this matter:

Don't Block on Async Code

quoted:

There are two best practices [...] that avoid this situation:

  • In your “library” async methods, use ConfigureAwait(false) wherever possible.
  • Don’t block on Tasks; use async all the way down.

Parallel Computing - It's All About the SynchronizationContext

Best practice to call ConfigureAwait for all server-side code

Should I call ConfigureAwait(false) on every awaited operation

So, the simplest solution is to add ConfigureAwait(false) everywhere in your code that is not known to run in the UI, or use async everywhere (never block on any task ever in your whole code, really everywhere, including in code you don't own).

IMHO, this is ridiculous... I personally use a Visual Studio extension that yells at me, if I forget to add it behind every async call :-)

Note there are some alternatives, for example: An alternative to ConfigureAwait(false) everywhere