Fix: DI Scoped Service Singleton Error - Dev Fix in 30 Seconds

Published: Jun 04, 2026 · By Kumar Kunal

The Error

InvalidOperationException: Cannot consume scoped service 'AppDbContext' from singleton 'DataService'

Quick Fix - 1 Minute

// BAD: Singleton consuming Scoped - Dev Fix below
// builder.Services.AddSingleton();

// GOOD: Make service Scoped or Transient builder.Services.AddScoped(); // Dev Fix: Match DbContext lifetime

// OR: Use IServiceScopeFactory if must be Singleton public class DataService { private readonly IServiceScopeFactory _scopeFactory; public DataService(IServiceScopeFactory scopeFactory) => _scopeFactory = scopeFactory;

public async Task Run()
{
    using var scope = _scopeFactory.CreateScope(); // Dev Fix
    var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
    // use db safely
}

}

Why This Happens

Singleton lives for app lifetime. Scoped lives per request. Singleton holding Scoped = DbContext reused across requests = crashes..NET 8 DI throws at startup to prevent this.

Real-World Scenario: IHostedService Captures DbContext

Most common.NET 8 startup crash. BackgroundService is Singleton by design:

// WRONG: Crashes on startup with InvalidOperationException
public class ReportGenerator : BackgroundService
{
    private readonly AppDbContext _db; // Scoped in Singleton = illegal
    private readonly ILogger<ReportGenerator> _logger;
    
    public ReportGenerator(AppDbContext db, ILogger<ReportGenerator> logger)
    {
        _db = db; // DI throws here
        _logger = logger;
    }
    
    protected override async Task ExecuteAsync(CancellationToken stoppingToken) { }
}

// RIGHT: Inject IServiceScopeFactory instead public class ReportGenerator : BackgroundService { private readonly IServiceScopeFactory _scopeFactory; private readonly ILogger<ReportGenerator> _logger;

public ReportGenerator(IServiceScopeFactory scopeFactory, ILogger&lt;ReportGenerator&gt; logger)
{
    _scopeFactory = scopeFactory; // Singleton - safe
    _logger = logger;
}

protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
    while (!stoppingToken.IsCancellationRequested)
    {
        using var scope = _scopeFactory.CreateScope(); // Dev Fix: New scope each loop
        var db = scope.ServiceProvider.GetRequiredService&lt;AppDbContext&gt;();
        
        var data = await db.Reports.ToListAsync(stoppingToken);
        // Process...
        
        await Task.Delay(TimeSpan.FromHours(1), stoppingToken);
    }
}

}

// Program.cs builder.Services.AddHostedService<ReportGenerator>(); // Singleton builder.Services.AddDbContext<AppDbContext>(); // Scoped

Key rule: IHostedService and BackgroundService are always Singleton. They can't inject Scoped services directly. Use IServiceScopeFactory to create a scope per unit of work.

Related Fixes You Should Know

DI lifetime bugs trigger these next:

FAQ

Q: Can I just make DbContext Singleton to fix this?

No. DbContext is not thread-safe. Singleton DbContext = multiple requests write to same ChangeTracker = data corruption + memory leaks. Keep it Scoped. Use factory pattern in Singletons.

Q: Why does the error only happen at startup?

.NET 8 validates DI graph on app.Run(). It walks the tree and fails fast if Singleton → Scoped found. This prevents runtime crashes. Older .NET versions crashed on first request instead.

Step-by-Step Debug

  1. Check lifetimes: DbContext is Scoped by default
  2. Never inject Scoped into Singleton
  3. Rule: Singleton → Singleton, Scoped → Scoped/Transient, Transient → Any
  4. If BackgroundService needs DbContext: use IServiceScopeFactory

Related Dev Fixes

Found this helpful?

Master C# with our complete course. Real apps, real skills, job-ready in 2 hours.

Share this fix: Twitter LinkedIn

Comments on Fix: DI Scoped Service Singleton Error - Dev Fix in 30 Seconds (0)

No comments yet. Be the first to share your thoughts!