Unknown Coder
Unknown Coder

Reputation: 1740

Cannot consume scoped service 'ApplicationDbContext' from singleton 'Microsoft.Extensions.Hosting.IHostedService'

I'm using .Net Core Background Service to Connect to Kafka and save messages to SQL Server. My Project Structure looks like this: enter image description here

In the Infrastructure Dependency, I have the following code to register Entity Framework using IConfiguration configuration passed from Worker's Program.cs file i.e. services.AddInfrastructure(configuration);

namespace JS.Svf.BackgroundServices.Infrastructure
{
    public static class DependencyInjection
    {
        public static IServiceCollection AddInfrastructure(this IServiceCollection services, IConfiguration configuration)
        {
            // Add all the dependencies required by Azure Functions.
            // From Infrastructure

            services.AddDbContext<ApplicationDbContext>(options =>
                       options.UseSqlServer(configuration.GetConnectionString("DefaultConnection"),
                           b => b.MigrationsAssembly(typeof(ApplicationDbContext).Assembly.FullName)));

            services.AddTransient<IApplicationDbContext>(provider => provider.GetRequiredService<ApplicationDbContext>());
            services.AddTransient<IProductRepository, ProductRepository>();
            services.AddTransient<ISupplierRepository, SupplierRepository>();
            return services;
        }
    }
}

I'm getting the following error after running the Background Service: Cannot consume scoped service 'ApplicationDbContext' from singleton 'Microsoft.Extensions.Hosting.IHostedService'

With reference, I came to know that we need to use IServiceScopeFactory but I'm bit clueless about how to use it with the current structure. Please advice.

The repository uses the ApplicationDbContext. How to use IServiceScopeFactory here?

namespace JS.Svf.Functions.Infrastructure.Persistence
{
    public class Repository<TEntity> : IRepository<TEntity> where TEntity : class
    {
        protected readonly ApplicationDbContext _context;

        public Repository(ApplicationDbContext context)
        {
            _context = context;
        }

        public void Add(TEntity entity)
        {
            _context.Set<TEntity>().Add(entity);
            _context.SaveChanges();
        }
    }
}

Upvotes: 2

Views: 5310

Answers (1)

DavidG
DavidG

Reputation: 119076

In your singleton service, the IHostedService, inject an IServiceScopeFactory into it and use that to create a scope and get a new DbContext from it. For example:

public class MyHostedService : IHostedService
{
    private readonly IServiceScopeFactory _scopeFactory;

    public MyHostedService(IServiceScopeFactory scopeFactory)
    {
        // Inject the scope factory
        _scopeFactory = scopeFactory;
    }

    private async Task SomeMethodThatNeedsTheContext()
    {
        // Create a new scope (since DbContext is scoped by default)
        using var scope = _scopeFactory.CreateScope();

        // Get a Dbcontext from the scope
        var context = scope.ServiceProvider
            .GetRequiredService<ApplicationDbContext>();           

        // Run a query on your context
        var quadrupeds = await context.Animals
            .Where(a => a.Legs == 4)
            .ToListAsync();
    }
}

Upvotes: 5

Related Questions