DEV Community

Dawn D
Dawn D

Posted on

Understand .NET ConfigureAwait(), .Result and await

Imagine you're going to a bank to file some paperwork.

You hand your files to a window, then you have two choices:

  1. Stand at the window, never leave until you get the result — even if an earthquake hits.
  2. Wait in the lobby and do your own thing, until you are called.

Option 2 is what await does. Option 1 is what .Result does. The trick is in which window calls you back — and that's where .ConfigureAwait(false) comes in.

The mental model

  • Request (you) = the calling code.
  • Bank vault = the async operation doing its work in the background.
  • Window / clerk = a thread that delivers the result back to you.
  • SynchronizationContext = the rule that says which window must deliver your result (e.g. "always window #3").

In a UI app (WPF, WinForms) or classic ASP.NET, there's always an assigned window — it's the UI thread or the request thread. In ASP.NET Core or a console app, there is no assignment — any free clerk can deliver the result.

The three options side by side

// 1. await — go wait in the lobby, come back to my ASSIGNED window
var result = await GetDataAsync();

// 1. await — go wait in the lobby, come back to my ASSIGNED window, .ConfigureAwait(true) is not neccessary
var result = await GetDataAsync().ConfigureAwait(true);

// 2. await + ConfigureAwait(false) — go wait in the lobby, come back to ANY free window
var result = await GetDataAsync().ConfigureAwait(false);

// 3. .Result — stand at the window, refuse to move until I have the receipt, even the earthquake come
var result = GetDataAsync().Result;
Enter fullscreen mode Exit fullscreen mode
  • await (default) = "I leave the lobby; when ready, deliver through my assigned window."
  • await ... .ConfigureAwait(false) = "I leave the lobby; when ready, deliver through any free window."
  • .Result = "I block the lobby; I will not move until the receipt is in my hand."

When to actually use it

  • In your own ASP.NET Core services and controllers: skip it. ASP.NET Core has no assigned windows — .ConfigureAwait(false) does nothing.
  • In library code (NuGet packages, shared infrastructure): use it everywhere as defensive armor — you don't know if a caller might block on .Result from WPF or classic ASP.NET.
  • In WPF / WinForms / classic ASP.NET app code: use await (default) when you need to touch the UI or request state after the await; switch to .ConfigureAwait(false) only for work that doesn't need the original context.
  • Never mix .Result (or .Wait()) with async code unless you have a very specific reason — that's the only situation where this whole discussion matters.

TL;DR

  • await = leave the lobby, come back through my window.
  • .ConfigureAwait(false) = leave the lobby, come back through any window.
  • .Result = block the lobby until the receipt arrives.
  • Deadlock = .Result blocks the very window the continuation insists on using.
  • ASP.NET Core has no assigned windows, so the whole problem doesn't exist there.

Top comments (0)