1

I have an ASP.NET Core 8 app with a long-lived service that refreshes an in-memory cache on a timer. I registered the service as a singleton (it’s a hosted background worker), and it needs to query the database periodically.

When I inject AppDbContext directly into the service constructor I get:

InvalidOperationException: Cannot consume scoped service 'AppDbContext' from singleton 'MyCacheService'.

Minimal Example:

// Program.cs
builder.Services.AddDbContext<AppDbContext>(options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("Default")));

builder.Services.AddHostedService<MyCacheService>(); // MyCacheService is long-lived/singleton
public class MyCacheService : BackgroundService
{
    private readonly AppDbContext _db; // <-- injecting scoped DbContext into singleton

    public MyCacheService(AppDbContext db)
    {
        _db = db; // causes InvalidOperationException at startup
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            var items = await _db.Items.ToListAsync(stoppingToken);
            // refresh cache...
            await Task.Delay(TimeSpan.FromMinutes(1), stoppingToken);
        }
    }
}

I know the exception comes from the lifetime mismatch (singleton depends on scoped), but I want to do this properly:

I’ve read hints about creating a scope manually with IServiceScopeFactory.

I’ve also seen AddDbContextFactory / IDbContextFactory recommended for background work.

Changing the service to scoped doesn’t fit my scenario because it’s a long-lived background worker -I’m using BackgroundService / IHostedService.

Here is my question: for a long-running background/hosted service that periodically queries the DB, what is the recommended, production-safe pattern to obtain a DbContext? Please show a short example of the recommended approach and mention any gotchas - concurrency, disposal, thread-safety, etc.

3
  • 2
    That's already explained in the .NET docs: Use scoped services within a BackgroundService. There are also a lot of duplicate questions. Given the official docs, what is the question ? The docs say you should use a Scoped service. In fact you should NEVER make a DbContext a singleton. A DbContext is a Unit-of-Work, not a database connection. If you don't dispose it, you risk persisting changes from a different action when you call SaveChanges Commented Sep 12 at 15:19
  • Transactions and database connections are another thing that shouldn't be long lived. Keeping a connection open also keeps any locks and resources used by that connection or transaction, blocking other connections, even in your own application. That's why database code always uses using blocks to ensure both connections and transactions are closed as soon as possible. Connection pooling at the ADO.NET level eliminates the cost of opening new connections by effectively reseting and reusing older connections. Commented Sep 12 at 15:25
  • It is just that, you can have a Singleton-registered DbContextFactory that can construct a DbContext on demand, which is itself scoped as a Unit of Work via using(). DbContext instances are intended to be alive only as long as absolutely necessary so even a long-running background service should only construct when needed, use, and dispose when completed. Commented Sep 14 at 0:13

0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.