# Using Scoped Services From Singletons in ASP.NET Core

> Did you ever need to inject a scoped service into a singleton service? I'll explain how you can solve this problem and safely use scoped services from within singletons in ASP.NET Core.

Published: 2024-02-17. Author: Milan Jovanović.

Canonical: https://milanjovanovic.tech/blog/using-scoped-services-from-singletons-in-aspnetcore

ASP.NET Core refuses to inject a scoped service into a singleton, so you inject `IServiceScopeFactory` instead, create a scope, and resolve the scoped service from that scope.
This is how you use an EF Core `DbContext` inside a background service.
In middleware, inject the scoped service as an `InvokeAsync` parameter so it shares the current request's scope.

Did you ever need to inject a scoped service into a singleton service?

I often need to resolve a scoped service, like the EF Core `DbContext`, in a background service.

Another example is when you need to resolve a scoped service in ASP.NET Core middleware.

If you ever tried this, you were probably greeted with an exception similar to this one:

```
System.InvalidOperationException: Cannot consume scoped service 'Scoped' from singleton 'Singleton'.
```

Today, I'll explain how you can solve this problem and safely use scoped services from within singletons in ASP.NET Core.

## ASP.NET Core Service Lifetimes

ASP.NET Core has three [service lifetimes](https://learn.microsoft.com/en-us/dotnet/core/extensions/dependency-injection#service-lifetimes):

- Transient
- Singleton
- Scoped

[Transient services](https://learn.microsoft.com/en-us/dotnet/core/extensions/dependency-injection#transient) are created each time they're requested from the service container.

[Scoped services](https://learn.microsoft.com/en-us/dotnet/core/extensions/dependency-injection#scoped) are created once within the scope's lifetime.
For ASP.NET Core applications, a new scope is created for each request.
This is how you can resolve scoped services within a given request.

ASP.NET Core applications also have a root `IServiceProvider` used to resolve [singleton services.](https://learn.microsoft.com/en-us/dotnet/core/extensions/dependency-injection#singleton)

So, what can we do if resolving a scoped service from a singleton throws an exception?

## The Solution - `IServiceScopeFactory`

What if you want to resolve a scoped service inside a [background service](https://milanjovanovic.tech/blog/running-background-tasks-in-asp-net-core)?

You can create a new scope (`IServiceScope`) with its own `IServiceProvider` instance.
The scoped `IServiceProvider` can be used to resolve scoped services.
When the scope is disposed, all disposable services created within that scope are also disposed.

Here's an example of using the `IServiceScopeFactory` to create a new `IServiceScope`.
We're using the scope to resolve the `ApplicationDbContext`, which is a scoped service.

The `BackgroundJob` is registered as a singleton when calling `AddHostedService<BackgroundJob>`.

```csharp {6,8,9,10}
public class BackgroundJob(IServiceScopeFactory serviceScopeFactory)
    : BackgroundService
{
    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        using IServiceScope scope = serviceScopeFactory.CreateScope();

        var dbContext = scope
            .ServiceProvider
            .GetRequiredService<ApplicationDbContext>();

        // Do some background processing with the EF database context.
        await DoWorkAsync(dbContext);
    }
}
```

## Scoped Services in Middleware

What if you want to use a scoped service in [ASP.NET Core middleware](https://milanjovanovic.tech/blog/3-ways-to-create-middleware-in-asp-net-core)?

Middleware is constructed once per application lifetime.

If you try injecting a scoped service, you'll get an exception:

```
System.InvalidOperationException: Cannot resolve scoped service 'Scoped' from root provider.
```

There are two ways to get around this.

First, you could use the previous approach with creating a new scope using `IServiceScopeFactory`.
You'll be able to resolve scoped services.
But, they won't share the same lifetime as the other scoped service in the same request.
This could even be a problem depending on your requirements.

Is there a better way?

Middleware allows you to inject scoped services in the `InvokeAsync` method.
The injected services will use the current request's scope, so they'll have the same lifetime as any other scoped service.

```csharp {5,7}
public class ConventionalMiddleware(RequestDelegate next)
{
    public async Task InvokeAsync(
        HttpContext httpContext,
        IMyScopedService scoped)
    {
        scoped.DoSomething();

        await _next(httpContext);
    }
}
```

## `IServiceScopeFactory` vs. `IServiceProvider`

You might see examples using the `IServiceProvider` to create a scope instead of the `IServiceScopeFactory`.

What's the difference between these two approaches?

The [`CreateScope` method from `IServiceProvider`](https://github.com/aspnet/DependencyInjection/blob/94b9cc9ace032f838e068702cc70ce57cc883bc7/src/DI.Abstractions/ServiceProviderServiceExtensions.cs#L125)
resolves an `IServiceScopeFactory` instance and calls `CreateScope()` on it:

```csharp
public static IServiceScope CreateScope(this IServiceProvider provider)
{
    return provider.GetRequiredService<IServiceScopeFactory>().CreateScope();
}
```

So, if you want to use the `IServiceProvider` directly to create a scope, that's fine.

However, the `IServiceScopeFactory` is a more direct way to achieve the desired result.

## Summary

Understanding the difference between Transient, Scoped, and Singleton lifetimes is crucial for managing dependencies in ASP.NET Core applications.

The `IServiceScopeFactory` provides a solution when you need to resolve scoped services from singletons.
It allows you to create a new scope, which you can use to resolve scoped services.

In middleware, we can inject scoped services into the `InvokeAsync` method.
This also ensures the services use the current request's scope and lifecycle.

Thanks for reading, and I'll see you next week!

---

## Frequently asked questions

### Can you inject a scoped service into a singleton in ASP.NET Core?

Not directly. The container throws an InvalidOperationException saying it cannot consume a scoped service from a singleton. The fix is to inject IServiceScopeFactory, create a new IServiceScope, and resolve the scoped service from that scope.

### What are the service lifetimes in ASP.NET Core?

There are three: transient services are created each time they are requested, scoped services are created once within the lifetime of a scope (ASP.NET Core creates a new scope for each request), and singleton services are resolved from the root IServiceProvider.

### How do you use an EF Core DbContext in a background service?

The DbContext is a scoped service, and a hosted background service is a singleton, so inject IServiceScopeFactory, call CreateScope, and resolve the DbContext from the scope's IServiceProvider. Disposing the scope also disposes every disposable service created within it.

### How do you use scoped services in ASP.NET Core middleware?

Inject them as parameters of the InvokeAsync method instead of the constructor. Middleware is constructed once per application lifetime, but InvokeAsync parameters resolve from the current request's scope, so they share the same lifetime as other scoped services in that request.

### What is the difference between IServiceScopeFactory and IServiceProvider for creating scopes?

There is no behavioral difference. The CreateScope extension method on IServiceProvider simply resolves an IServiceScopeFactory and calls CreateScope on it. Using IServiceScopeFactory directly is just the more direct way to achieve the same result.
