Cannot access a disposed object in ASP.NET Core when injecting DbContext

The “Cannot access a disposed object” exception in ASP.NET Core, especially when using Entity Framework’s DbContext, is a common issue developers face. This article explores the root causes, prevention strategies, and best practices to avoid this error in modern ASP.NET Core applications.

Understanding the Error

The ObjectDisposedException typically occurs when an attempt is made to use an object that has already been disposed. In the context of ASP.NET Core and Entity Framework, this often involves the DbContext. The error message generally looks like this:

System.ObjectDisposedException: Cannot access a disposed object.

This exception usually arises from incorrect service lifetimes, improper asynchronous programming, or manually disposing of the DbContext.

Common Causes and Solutions

1. Manual Disposal of DbContext

ASP.NET Core’s dependency injection (DI) framework manages the lifecycle of DbContext instances. Manually disposing of a DbContext instance resolved through DI can lead to this error.

Solution: Avoid wrapping DbContext in a using statement or explicitly calling Dispose(). Let the DI container manage the lifecycle of the context.

// Incorrect
using (var context = new ApplicationDbContext()) {
    // ...
}

// Correct - Let DI manage the lifecycle
public class MyService {
    private readonly ApplicationDbContext _context;

    public MyService(ApplicationDbContext context) {
        _context = context;
    }/

    public void DoWork() {
        // Use _context here
    }
}

2. Incorrect Service Lifetime Configuration

DbContext must be registered with a scoped lifetime, which aligns with the lifecycle of a single web request. Registering it as a singleton or transient can lead to disposed object issues.

  • Solution: Ensure proper service registration in Startup.cs or Program.cs:
services.AddDbContext<ApplicationDbContext>(options =>
    options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

3. Asynchronous Programming Pitfalls

  • Unawaited Asynchronous Calls: Failing to await asynchronous methods can result in the DbContext being disposed before the operation completes.
  • Using ****async void: Avoid using async void as it can lead to unobserved exceptions and premature disposal of the DbContext.
  • Solution: Properly await all asynchronous calls and ensure methods return a Task.
// Correct
public async Task ProcessDataAsync() {
    await _context.MyEntities.ToListAsync();
}

4. **Background Tasks Accessing **DbContext

Starting new threads or background tasks that try to access a DbContext from the main thread can lead to this error. Each thread or task should manage its own DbContext instance.

  • Solution: Use scoped services for background tasks and create new DbContext instances where necessary.
Task.Run(async () => {
    using (var scope = serviceProvider.CreateScope()) {
        var context = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
        await context.MyEntities.ToListAsync();
    }
});

Best Practices

1. Service Registration

Always register DbContext with a scoped lifetime using AddDbContext.

2. Avoid Manual Disposal

Let the DI container handle the lifecycle of DbContext instances.

3. Proper Asynchronous Programming

Always await asynchronous calls and avoid async void methods.

4. Manage Background Tasks Properly

Ensure that background tasks have their own service scopes and DbContext instances.

5. Use Logging to Debug

Enable detailed logging in ASP.NET Core to identify where the DbContext might be disposed prematurely.

services.AddLogging(logging => {
    logging.AddConsole();
    logging.AddDebug();
});

Conclusion

By understanding the lifecycle of DbContext, avoiding manual disposal, and following best practices, you can prevent the “Cannot access a disposed object” exception in ASP.NET Core applications. Proper service configuration, disciplined asynchronous programming, and careful handling of background tasks are key to ensuring stable and maintainable code.

Unknown's avatar

Author: Peter Groenewegen

Hi, I’m Peter Groenewegen—a technologist, developer advocate, and AI enthusiast passionate about building tools that truly fit people’s workflows. My journey in tech has been one of innovation, collaboration, and a relentless curiosity to make the complex simple.

14 thoughts on “Cannot access a disposed object in ASP.NET Core when injecting DbContext”

  1. Hi, Thanks for the article. I encountered the cannot access dispose exception while I use the Task.run() inside a async method. Actually the Task.run() executes in loop for calling a service method. After the 1st call, am getting the issue, may be due to the dependency injection disposes the client after the 1st call. how to create new instance of my DI object for each service call?

    Like

Leave a reply to Sean Fackrell Cancel reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.