Entity Framework DbContext is NOT disposed using dependency injection

asp.net-core-webapi c# dependency-injection entity-framework-core

Question

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

  • reordering 'AddTransient' without success (as expected)
  • using 'AddScoped' instead of 'AddTransient'

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

  • 2020-03-24 21:09:29.5727|Options injected in DataContext
  • 2020-03-24 21:09:29.6064|Authentication injected in DataContext
  • 2020-03-24 21:09:29.6064|Logger injected in DataContext
  • 2020-03-24 21:09:29.6262|Created DataContext 1ddd98a1-a8f9-4096-8a11-c0b4d40d01ae
  • 2020-03-24 21:09:30.1918|Logger injected in CustomerService
  • 2020-03-24 21:09:30.2200|DataContext injected in CustomerService
  • 2020-03-24 21:09:30.2300|Mapper injected in CustomerService
  • 2020-03-24 21:09:30.2482|Authentication injected in CustomerService
  • 2020-03-24 21:09:30.2482|Created CustomerService 5b446267-d908-4291-9918-af1841324708
  • 2020-03-24 21:09:30.2769|Logger injected in CustomerController
  • 2020-03-24 21:09:30.2769|CustomerService injected in CustomerController
  • 2020-03-24 21:09:30.3186|CustomerController.GetCustomer(4)
  • 2020-03-24 21:09:35.0599|Disposing CustomerService 5b446267-d908-4291-9918-af1841324708

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!

1
0
3/27/2020 2:31:56 PM

Popular Answer

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>();
2
3/24/2020 7:46:26 PM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow