I'm trying to pass EF Core Dbcontext
to my BackgroundService
through dependency injection but somehow cannot get the hang of it.
Can someone tell me what I'm doing wrong and how to do it right/better/easier/another way (not cumbersome if possible)?
I'm using services.AddDbContext<MyDbContext>
to add the DbContext in HostBuilder
, then trying to receive it in the constructor of my BackgroundService
.
I added the DbContext
constructor receiving the DbContextOptions<MyDbContext> options
and passing it to the base constructor of DbContext
in my context, which is the way described in the documentation
Here's the exception I keep getting when starting the application:
System.AggregateException
HResult=0x80131500
Message=Some services are not able to be constructed (Error while validating the service descriptor 'ServiceType: Microsoft.Extensions.Hosting.IHostedService Lifetime: Singleton ImplementationType: XXXX.SenderService': Cannot consume scoped service 'XXXX.Entities.MyDbContext' from singleton 'Microsoft.Extensions.Hosting.IHostedService'.)
Source=Microsoft.Extensions.DependencyInjection
StackTrace:
at Microsoft.Extensions.DependencyInjection.ServiceProvider..ctor(IEnumerable`1 serviceDescriptors, ServiceProviderOptions options)
at Microsoft.Extensions.DependencyInjection.ServiceCollectionContainerBuilderExtensions.BuildServiceProvider(IServiceCollection services, ServiceProviderOptions options)
at Microsoft.Extensions.DependencyInjection.DefaultServiceProviderFactory.CreateServiceProvider(IServiceCollection containerBuilder)
at Microsoft.Extensions.Hosting.Internal.ServiceFactoryAdapter`1.CreateServiceProvider(Object containerBuilder)
at Microsoft.Extensions.Hosting.HostBuilder.CreateServiceProvider()
at Microsoft.Extensions.Hosting.HostBuilder.Build()
at XXXX.Program.Main(String[] args) in C:\WORK\REPOS\CRR\Main\XXXX\Program.cs:line 16
This exception was originally thrown at this call stack:
[External Code]
Inner Exception 1:
InvalidOperationException: Error while validating the service descriptor 'ServiceType: Microsoft.Extensions.Hosting.IHostedService Lifetime: Singleton ImplementationType: XXXX.SenderService': Cannot consume scoped service 'XXXX.Entities.MyDbContext' from singleton 'Microsoft.Extensions.Hosting.IHostedService'.
Inner Exception 2:
InvalidOperationException: Cannot consume scoped service 'XXXX.Entities.MyDbContext' from singleton 'Microsoft.Extensions.Hosting.IHostedService'.
Here's the Program.cs:
public static class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).ConfigureLogging(config => config.ClearProviders())
.Build()
.Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureServices((builderContext, services) =>
services.AddDbContext<MyDbContext>(options =>
options.UseSqlServer(builderContext.Configuration
.GetConnectionString(nameof(MyDbContext)))
).AddHostedService<SenderService>())
.UseWindowsService();
}
SenderService.cs:
public class SenderService : BackgroundService
{
public SenderService(IConfiguration configuration, MyDbContext context)
{
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
}
}
and MyDbContext:
public class MyDbContext : DbContext
{
public MyDbContext(DbContextOptions<MyDbContext> options) : base(options) { }
public DbSet<XXXX> XXXX { get; set; }
}
In the end, I figured it out!
Problem description
What I'm basically doing is using
ConfigureServices
toAddScoped
object, which is what happens whenAddDbContext<MyDbContext>
is called with only the delegate action filling out theDbContextOptionsBuilder
that is then passed to myMyDbcontext
constructor.The dog is buried in adding the context as
scoped
object, while Service needs it assingleton
to accept it in its constructor.How to remedy that
Well, I can update the piece of code inside the delegate in
ConfigureServices
to treat the DbContext as a singleton:Or, better, DON'T PASS CONTEXT AS SINGLETON TO THE SERVICE, CREATE IT WHEN NEEDED!
Which I can do for example by passing just the optionsBuilder like this: