Entity Framework
async calls
performance issues
database
troubleshooting

Entity Framework hangs when using async calls

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

Introduction

When Entity Framework appears to hang during async operations, the most common cause is not that async itself is broken. It is usually one of three problems: blocking on an async task with .Result or .Wait(), using the same DbContext concurrently, or waiting on a database call that is itself blocked by a long query or lock.

Do Not Block on Async EF Calls

The classic deadlock pattern is calling an async EF method and then waiting synchronously for it to finish.

csharp
var users = context.Users.ToListAsync().Result;

or:

csharp
context.SaveChangesAsync().Wait();

This is dangerous because the async continuation may need to resume on a synchronization context that the current thread is already blocking. In UI applications and older ASP.NET contexts, that can look exactly like a hang.

The correct pattern is to keep the whole call chain async.

csharp
1public async Task<List<User>> LoadUsersAsync()
2{
3    return await context.Users.ToListAsync();
4}

If one part of the call chain blocks, the benefit of async can collapse into a deadlock or severe responsiveness issue.

A DbContext Is Not for Parallel Use

Another common issue is starting multiple async operations on the same DbContext at once.

For example, this is a bad pattern:

csharp
1var task1 = context.Users.ToListAsync();
2var task2 = context.Orders.ToListAsync();
3
4await Task.WhenAll(task1, task2);

A single DbContext is not designed for concurrent operations. Even when the code compiles, overlapping usage can cause hangs, exceptions, or undefined access patterns.

If you truly need parallel work, use separate contexts.

csharp
1await using var context1 = new AppDbContext();
2await using var context2 = new AppDbContext();
3
4var usersTask = context1.Users.ToListAsync();
5var ordersTask = context2.Orders.ToListAsync();
6
7await Task.WhenAll(usersTask, ordersTask);

Check the Database Side Too

Sometimes the code is perfectly async and the real delay is in the database. Long-running queries, blocked transactions, lock contention, or missing indexes can make an EF call look hung even though it is just waiting.

That is why you should inspect:

  • SQL execution time
  • blocking sessions
  • transaction scope length
  • generated query shape
  • missing indexes or table scans

Enable EF logging or SQL profiling so you can see the exact query being executed.

csharp
optionsBuilder
    .UseSqlServer(connectionString)
    .LogTo(Console.WriteLine);

If the query sits in the database for a long time, the fix is not in await. It is in the SQL workload.

Avoid Async All the Way Except Where Necessary

Async improves scalability when used correctly, but using it halfway often causes the worst problems. A healthy async EF flow usually looks like this:

  • async controller or service method
  • awaited EF query or save call
  • no synchronous blocking wrapper around the task
  • one context used by one logical operation at a time

That design keeps the control flow simple and avoids hidden blocking.

ConfigureAwait(false) Is Not a Magic Repair Tool

In library code, ConfigureAwait(false) can help avoid context capture issues, but it is not the first answer to every EF async hang.

csharp
var users = await context.Users.ToListAsync().ConfigureAwait(false);

This can be useful in lower-level library code, but if the real problem is .Result, a bad query, or shared DbContext concurrency, ConfigureAwait(false) will not solve the root cause.

Common Pitfalls

  • Calling .Result or .Wait() on EF async methods is the most common deadlock pattern.
  • Starting multiple async EF operations on the same DbContext creates unsupported concurrent usage.
  • Assuming every "hang" is an async bug ignores the possibility of a slow SQL query or database lock.
  • Sprinkling ConfigureAwait(false) everywhere without fixing the actual blocking pattern treats the symptom rather than the cause.
  • Mixing sync and async data-access methods in the same request flow makes behavior harder to reason about and debug.

Summary

  • EF async hangs are usually caused by blocking async tasks, concurrent DbContext usage, or database-side waiting.
  • Keep the whole call chain async and avoid .Result and .Wait().
  • Use one DbContext per logical operation, not for overlapping async work.
  • Log the generated SQL so you can separate application deadlocks from slow database queries.
  • Fix the actual blocking pattern instead of assuming the async API itself is the problem.

Related reading
Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

All Rights Reserved.