I'm using EF Core together with Postgres (probably doesn't matter) inside an .NET Core 3.1 console application.
The program is using a shared project (among other components of the solution) with all business logic implemented using a simple CQRS type pattern with Mediator.
At one place I'm retrieving large objects from the database (10 - 100MB) in size. This is not very frequent so by itself is not an issue. It takes a fraction of a second on modern hardware. The problem is that for some reason those objects get cached in the datacontext between command executions, like the datacontext doesn't get disposed.
I don't understand why, because I registered the DbContext inside the DI container (the standard built in one) as transient. How I understand it it should create a new instance every time it's requested and the garbage collector should take care of the rest.
The registration code is something like this:
static IServiceProvider ConfigureServiceProvider()
{
IServiceCollection services = new ServiceCollection();
DbContextOptions<MyAppDbContext> dbContextOptions = new DbContextOptionsBuilder<MyAppDbContext>()
.UseNpgsql(Configuration.GetConnectionString("MyApp.Db"))
.Options;
services.AddSingleton(dbContextOptions);
services.AddDbContext<MyAppDbContext>(options => options.UseNpgsql(Configuration.GetConnectionString("MyApp.Db"), options => options.EnableRetryOnFailure()), ServiceLifetime.Transient);
services.AddTransient<IMyAppDbContext>(s => s.GetService<MyAppDbContext>());
// (...)
}
Then the command is using it in this way:
public class RecalculateSomething : IRequest
{
public Guid SomeId { get; set; }
public class Handler : IRequestHandler<RecalculateSomething>
{
private IMyAppDbContext context;
private readonly IMediator mediator;
public Handler(IMyAppDbContext context, IMediator mediator)
{
this.context = context ?? throw new ArgumentNullException(nameof(context));
this.mediator = mediator ?? throw new ArgumentNullException(nameof(mediator));
}
public async Task<Unit> Handle(RecalculateSomething request, CancellationToken ct)
{
// (...)
}
}
}
Does anyone know what the problem is? Is it something I'm doing wrong configuring the DI container? Or something else, like a reference I'm holding onto somewhere (couldn't find it). What would be the best way to approach debugging an issue like this?
BTW I have "fixed it" by just forcing it to create a new DbContext each time from DbContextOptions, but that's more of a workaround. Would like to know what the core issue is.