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
ConfigureServicestoAddScopedobject, which is what happens whenAddDbContext<MyDbContext>is called with only the delegate action filling out theDbContextOptionsBuilderthat is then passed to myMyDbcontextconstructor.The dog is buried in adding the context as
scopedobject, while Service needs it assingletonto accept it in its constructor.How to remedy that
Well, I can update the piece of code inside the delegate in
ConfigureServicesto 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: