I have recently stumbled across the fact that I cannot use the same instance of DBContext in separate threads. I have two services that share the same DBContext so I end up with an Exception
System.InvalidOperationException: 'A second operation started on this context before a previous operation completed. This is usually caused by different threads using the same instance of DbContext. For more information on how to avoid threading issues with DbContext, see https://go.microsoft.com/fwlink/?linkid=2097913.'
So my code is mostly generated by ASP.Net core wizard
// program.cs
private static void ConfigureServices(string settings, IServiceCollection services)
{
services.AddDbContext<MMCC.Terminal.Service.Data.TerminalDbContext>((provider, options) =>
{ options.UseNpgsql(configuration.GetConnectionString(nameof(TerminalDbContext)));
});
}
public MyService1(TerminalDbContext dbTerminal)
{
_dbTerminal = dbTerminal;
}
public MyService2(TerminalDbContext dbTerminal)
{
_dbTerminal = dbTerminal;
}
Usage
void Run()
{
_hourTimer = new Timer(UpdateOnceInHour, null, 0, 60 * 60 * 1000);
_minuteTimer = new Timer(UpdateEveryMinute, null, 0, 1 * 60 * 1000);
}
private async void UpdateOnceInHour(object state)
{
_mService1.DoSomething()
}
private async void UpdateOnceInHour(object state)
{
_mService2.DoSomething()
}
So here is when I have an exception.
// Service 1
// thread 1
private DoSomething()
{
await _dbTerminal.SomeTable1.ToListAsync();
}
// Service 2
// thread 2
private DoSomething()
{
await _dbTerminal.SomeTable2.ToListAsync();
}
I am trying to figure out how to solve this problem. Is there any standard pattern? I tried refactoring my code, and instead of injecting TerminalDbContext into Service1, Service2 I do inject IServiceProvider, and then do GetService for TerminalDbContext but it seems that I end up with the same instance of DBContext.