When working with dependency injection (DI) in ASP.NET Core, developers often stumble upon a tricky problem:
How do I resolve a scoped service (like DbContext
) outside the normal HTTP request pipeline?
That’s where IServiceScopeFactory.CreateScope()
comes into play.
The Problem
ASP.NET Core services have three main lifetimes:
- Singleton → Created once for the entire application.
- Scoped → Created once per HTTP request.
- Transient → Created every time it’s requested.
Normally, in controllers or middleware, you don’t worry about scopes. ASP.NET Core automatically creates a scope for each request.
But what if you’re outside of a request? For example:
- Running a background service (
IHostedService
,BackgroundService
) - Executing a scheduled job
- Writing a console app with the Generic Host
If you try to inject a DbContext
(scoped service) directly into a singleton service like BackgroundService
, it fails. The DI container doesn’t know how to manage its lifetime.
The Solution: IServiceScopeFactory.CreateScope()
IServiceScopeFactory
allows you to manually create a DI scope.
Inside that scope, you can safely resolve scoped services (like DbContext
) and they’ll be disposed automatically when the scope ends.
Example: Using in a Background Service
public class MyBackgroundService : BackgroundService
{
private readonly IServiceScopeFactory _scopeFactory;
public MyBackgroundService(IServiceScopeFactory scopeFactory)
{
_scopeFactory = scopeFactory;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
using (var scope = _scopeFactory.CreateScope())
{
var dbContext = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
// Use DbContext safely here
var users = await dbContext.Users.ToListAsync();
}
await Task.Delay(10000, stoppingToken);
}
}
}
Congratulations on creating your first production ready background job.
Keep learning, keep progressing..
Top comments (0)