Asynchronous method with context dispose
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
A disposed-context error in C# async code usually means an object such as DbContext outlived the scope that created it. The most common cause is starting asynchronous work that continues after the request or dependency-injection scope has already ended. Fixing it is mostly about lifetime design, not about adding random ConfigureAwait calls or retry logic.
Understand Why the Context Gets Disposed
In ASP.NET Core, a scoped dependency such as DbContext is usually created per request and disposed when the request scope ends. If a method starts work and does not await it before returning, the request may finish while the task still tries to use the context.
A simplified bad pattern looks like this:
The task may still be running after the request scope has been torn down. At that point, _db is disposed and the failure shows up far away from the original mistake.
Await Scoped Work Before Returning
If the work belongs to the request, keep it inside the request lifetime and await it directly.
Then await it in the controller:
This keeps the query and the context inside the same scope, which is what scoped services are designed for.
Do Not Use Fire-and-Forget with Scoped Services
If work must continue after the request, do not capture request-scoped services and hope they survive. Create a new scope inside a background worker instead.
This gives the background task its own lifetime boundary instead of borrowing the request's boundary.
Use IDbContextFactory When It Fits the Design
For code that needs to create contexts on demand, IDbContextFactory is often cleaner than carrying a scoped context around.
This pattern makes ownership explicit. The method creates the context, uses it, and disposes it in one place.
Lazy Execution Can Hide the Real Bug
Another failure mode is returning an IQueryable or deferred sequence from a scope that is already ending.
The query is not executed yet. If enumeration happens after the context is gone, the error appears later and looks confusing. Materialize the data inside the valid lifetime if the caller should not own the context.
Common Pitfalls
- Starting fire-and-forget tasks that capture scoped services such as
DbContext. - Returning deferred queries that are executed only after the context has already been disposed.
- Using
Task.Runas if it were a fix for dependency lifetime problems. - Sharing one context across concurrent operations without a clear ownership boundary.
- Forgetting
await usingwhen a factory-created context supports asynchronous disposal.
Summary
- Disposed-context errors in async code are usually lifetime mismatches.
- Await request-scoped work before the scope ends.
- For background tasks, create a new dependency-injection scope or use a context factory.
- Materialize results inside the valid context lifetime when callers should not own the query.
- Treat disposal problems as ownership-design issues, not as random async glitches.

