Knowing When, Why, and How to Use IServiceScopeFactory in.NET (With Real Examples)

Dependency injection (DI) plays a key role in managing object lifetimes and dependencies in contemporary.NET applications, particularly in ASP.NET Core and background services. Singleton and transient services are simple to comprehend, but scoped services—particularly those that are not part of the request pipeline—become more complex.

This is where IServiceScopeFactory becomes crucial.

This article breaks down.

  • What IServiceScopeFactory is
  • When and why to use it
  • Real-world examples
  • Pitfalls to avoid
  • When not to use it

What is IServiceScopeFactory?

IServiceScopeFactory is an interface provided by the .NET DI container that allows you to create a new service scope manually.

When you call CreateScope(), it returns an IServiceScope, which has its own IServiceProvider. You can use this scoped provider to resolve scoped services, which would otherwise be inaccessible during a web request.

public interface IServiceScopeFactory
{
    IServiceScope CreateScope();
}

Why is it needed?

Typically, scoped services (like a DbContext) are created per HTTP request . But what if you’re in a background task or a singleton service and need to use a scoped service?

You can’t directly inject a scoped service into a singleton. That would break the lifetime rules and throw an exception (or worse, cause memory leaks).

That’s where IServiceScopeFactory shines. It allows you to safely create a scope and use scoped services, even from singletons or hosted services.

When to Use IServiceScopeFactory?

Let’s look at practical scenarios.

Using Scoped Services in Hosted Background Services

Let’s say you’re running a background task that syncs data every few minutes, and you need to access MyDbContext.

MyDbContext is registered as scoped, but BackgroundService is a singleton.

Correct way of using IServiceScopeFactory.

public class DataSyncService : BackgroundService
{
    private readonly IServiceScopeFactory _scopeFactory;

    public DataSyncService(IServiceScopeFactory scopeFactory)
    {
        _scopeFactory = scopeFactory;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            using var scope = _scopeFactory.CreateScope();
            var dbContext = scope.ServiceProvider.GetRequiredService<MyDbContext>();

            var records = await dbContext.Records.ToListAsync();
            // process records...

            await Task.Delay(TimeSpan.FromMinutes(5), stoppingToken);
        }
    }
}

This safely creates a scope and ensures all scoped services are disposed of properly.

Queue-based Processing (Worker Pattern)

Let’s say you’re queuing jobs and processing them using a singleton MessageProcessor. You need access to scoped services per message.

public class MessageProcessor
{
    private readonly IServiceScopeFactory _scopeFactory;

    public MessageProcessor(IServiceScopeFactory scopeFactory)
    {
        _scopeFactory = scopeFactory;
    }

    public async Task ProcessMessageAsync(MyMessage message)
    {
        using var scope = _scopeFactory.CreateScope();
        var handler = scope.ServiceProvider.GetRequiredService<IMessageHandler>();
        await handler.HandleAsync(message);
    }
}

This ensures every message gets its own fresh scope.

On-Demand Scoped Dependencies in Console Apps or Middleware

In a console app or custom middleware where there’s no implicit scope, you can create one manually.

var serviceScopeFactory = serviceProvider.GetRequiredService<IServiceScopeFactory>();
using var scope = serviceScopeFactory.CreateScope();

var db = scope.ServiceProvider.GetRequiredService<MyDbContext>();

When Not to Use IServiceScopeFactory?

While it’s powerful, misuse can create hard-to-debug memory leaks or broken DI lifetimes.

1. Don’t Use IServiceScopeFactory Inside Controllers

Controllers and Razor Pages already operate within a scope—no need to create another.

Bad Example

public class HomeController : Controller
{
    private readonly IServiceScopeFactory _scopeFactory;

    public HomeController(IServiceScopeFactory scopeFactory) => _scopeFactory = scopeFactory;

    public IActionResult Index()
    {
        using var scope = _scopeFactory.CreateScope();
        var db = scope.ServiceProvider.GetRequiredService<MyDbContext>();
        // Not needed!
    }
}

Good example

public class HomeController : Controller
{
    private readonly MyDbContext _db;

    public HomeController(MyDbContext db) => _db = db;

    public IActionResult Index()
    {
        var data = _db.Records.ToList();
        return View(data);
    }
}

2. Don’t Keep a Scope Alive Too Long

A scope is meant to be short-lived (per request or operation). Don’t hold onto a scope and reuse it across multiple operations.

This can lead to,

  • Memory leaks
  • Database connection leaks
  • Incorrect disposal of scoped services

Key Benefits of IServiceScopeFactory

  • Enables the use of scoped services in singleton/background services
  • Ensures services are disposed of properly
  • Helps maintain correct DI lifetimes
  • Prevents common anti-patterns like injecting scoped into a singleton

Alternative: Use IServiceProvider.CreateScope()

If you’re in Program.cs or somewhere you already have access to IServiceProvider, you can call.

using var scope = app.Services.CreateScope();
var myService = scope.ServiceProvider.GetRequiredService<IMyService>();

But in long-lived services, it’s better to inject IServiceScopeFactory to avoid capturing the root IServiceProvider.

If you’re building long-running applications or background services in .NET, mastering IServiceScopeFactory will make your code cleaner, safer, and more maintainable.

Thank you for reading. Please share your questions, thoughts, or feedback in the comments section. I appreciate your feedback and encouragement.

Best and Most Recommended ASP.NET Core 10.0 Hosting

Fortunately, there are a number of dependable and recommended web hosts available that can help you gain control of your website’s performance and improve your ASP.NET Core 10.0 web ranking. HostForLIFE.eu is highly recommended. In Europe, HostForLIFE.eu is the most popular option for first-time web hosts searching for an affordable plan. Their standard price begins at only €3.49 per month. Customers are permitted to choose quarterly and annual plans based on their preferences. HostForLIFE.eu guarantees “No Hidden Fees” and an industry-leading ’30 Days Cash Back’ policy. Customers who terminate their service within the first thirty days are eligible for a full refund.

By providing reseller hosting accounts, HostForLIFE.eu also gives its consumers the chance to generate income. You can purchase their reseller hosting account, host an unlimited number of websites on it, and even sell some of your hosting space to others. This is one of the most effective methods for making money online. They will take care of all your customers’ hosting needs, so you do not need to fret about hosting-related matters.