hardConceptScenarioMidSeniorStaff
Why does calling .Result or .Wait() on an async method deadlock, and how do you fix it properly?
Blocking on async code with .Result or .Wait can deadlock when the awaited continuation needs the same SynchronizationContext that is blocked. In ASP.NET Core the common failure is thread-pool starvation; the fix is async all the way up.
5 min readUpdated 2026-08-15
Answer
Short answer
Calling .Result or .Wait() on async code can deadlock when the continuation tries to resume on a context that the caller is blocking, such as a UI thread or ASP.NET Framework request context. Prefer await all the way up; in ASP.NET Core, blocking is still dangerous because it can starve the thread pool.
Was this answer helpful?
Likely follow-ups
- Why does ConfigureAwait(false) have to be applied to every await in the call chain to be effective?
- What is the difference between .Result and GetAwaiter().GetResult(), and why does neither one solve this?
- How does the thread pool decide to inject new threads, and why does that make starvation look like a slow leak?
- When is Task.Run(() => FooAsync()).GetAwaiter().GetResult() a defensible last resort, and what does it cost you?
Related questions
- A client disconnects but your server keeps working on their request. How does cancellation actually propagate in .NET?mediumAlso on aspnet-core4 min
- A request fails but your Express error-handling middleware never runs. How do you work out why?mediumAlso on async-await4 min
- You added an authorisation policy to an ASP.NET Core endpoint and it is not being enforced. Where do you look?mediumAlso on aspnet-core4 min
- You kick off background work from a controller action and it throws once the response has gone out. What is happening?mediumAlso on aspnet-core5 min