Berrepoot
Berrepoot

Reputation: 141

Entity Framework DbContext is NOT disposed using dependency injection

I have the following setup in a solution:

EDIT: Demo solution can be found here

ASP.NET Core Web API:

public class MyController : ControllerBase
{
    private readonly IMyService _service;
    public MyController(IMyService service)
        {
             _service = service;
        }
}

Service layer:

public class MyService: IMyService, IDisposable
{
    private readonly IDataContext _context;
    public MyService(IDataContext context)
        {
             _context = context;
        }
}

Entity Framework Core:

public class DataContext : DbContext, IDataContext, IDisposable
{
    public DataContext(DbContextOptions<DataContext> options, IAuthenticationService authentication, ILogger<DataContext> logger) : base(options) 
        {
            ...
        }
}

A 'CompositionRoot' to link it all together using Microsoft.Extensions.DependencyInjection:

services.AddDbContext<DataContext>(options =>  options.UseSqlServer(configuration.GetConnectionString("myConnection")), ServiceLifetime.Transient);
services.AddTransient<IMyService, MyService>();
//EDIT: removed this line
//services.AddTransient<IDataContext, DataContext>(); 

This all works as expected but my DataContext is never disposed. I've added logs in the dispose methods to monitor this behaviour but I can't figure out why this is happening (or not happening in this case). I've tried

I'm using an interface to mock the DbContext in my unit tests, but I want my DbContext to be disposed to. Anyone an idea on why this happens and how to solve it?

EDIT: some extra logs

EDIT march 25: I've tried using the DataContext without an interface but the problem still exists. I realy have no clue what I'm doing wrong!

Upvotes: 3

Views: 2061

Answers (2)

Sergey Skrynnik
Sergey Skrynnik

Reputation: 21

Also faced with this issue (is it actually issue?). I have ASP.Net Core WebApi project (framework = net 5.0) and use AddDbContext to inject it to the MVC-Controller. It should add db-context as "Scoped" according to the article. As per my expectations, in this case db-context should be instantiated per every http request (that's it) and be disposed implicitly, in scope of MVC-Controller lifetime - but it's does not happen for some reason.. Potencially, it may result in "The instance of entity type {} cannot be tracked because another instance with the key value {} is already being tracked." (it's a reason why I have come here)

I belive, it may be fixed by added "using" construction in the code or by callind Dispose() from the Controller like that

protected override void Dispose(bool disposing = true)
        {
            Console.WriteLine("Controller dispose.");
            _dbContext.Dispose(); //your db-context (injected in controller)
            base.Dispose(disposing);
        }

but not sure it's rigth solution..

Upvotes: 1

Nkosi
Nkosi

Reputation: 247561

You are not registering the DbContext correctly

Use the following overload of AddDbContext

services.AddDbContext<IDataContext, DataContext>(options =>  
    options.UseSqlServer(configuration.GetConnectionString("myConnection")));

Which will associate the interface/abstraction with the concrete implementation.

And remove the transient registration

services.AddTransient<IDataContext, DataContext>();

Upvotes: 2

Related Questions