title | description | author | ms.author | ms.date | ms.topic |
---|---|---|---|---|---|
Use scoped services within a BackgroundService |
Learn how to use scoped services within a BackgroundService in .NET. |
IEvangelist |
dapine |
12/13/2023 |
tutorial |
When you register implementations of xref:Microsoft.Extensions.Hosting.IHostedService using any of the xref:Microsoft.Extensions.DependencyInjection.ServiceCollectionHostedServiceExtensions.AddHostedService%2A extension methods - the service is registered as a singleton. There may be scenarios where you'd like to rely on a scoped service. For more information, see Dependency injection in .NET: Service lifetimes.
In this tutorial, you learn how to:
[!div class="checklist"]
- Resolve scoped dependencies in a singleton xref:Microsoft.Extensions.Hosting.BackgroundService.
- Delegate work to a scoped service.
- Implement an
override
of xref:Microsoft.Extensions.Hosting.BackgroundService.StopAsync(System.Threading.CancellationToken)?displayProperty=nameWithType.
[!INCLUDE workers-samples-browser]
- The .NET 8.0 SDK or later
- A .NET integrated development environment (IDE)
- Feel free to use Visual Studio
[!INCLUDE file-new-worker]
To use scoped services within a BackgroundService
, create a scope. No scope is created for a hosted service by default. The scoped background service contains the background task's logic.
:::code source="snippets/workers/scoped-service/IScopedProcessingService.cs":::
The preceding interface defines a single DoWorkAsync
method. To define the default implementation:
- The service is asynchronous. The
DoWorkAsync
method returns aTask
. For demonstration purposes, a delay of ten seconds is awaited in theDoWorkAsync
method. - An xref:Microsoft.Extensions.Logging.ILogger is injected into the service.:
:::code source="snippets/workers/scoped-service/DefaultScopedProcessingService.cs":::
The hosted service creates a scope to resolve the scoped background service to call its DoWorkAsync
method. DoWorkAsync
returns a Task
, which is awaited in ExecuteAsync
:
Replace the existing Worker
class with the following C# code, and rename the file to ScopedBackgroundService.cs:
:::code source="snippets/workers/scoped-service/ScopedBackgroundService.cs" highlight="22-28":::
In the preceding code, an explicit scope is created and the IScopedProcessingService
implementation is resolved from the dependency injection service scope factory. The resolved service instance is scoped, and its DoWorkAsync
method is awaited.
Replace the template Program.cs file contents with the following C# code:
:::code source="snippets/workers/scoped-service/Program.cs" highlight="4-5":::
The services are registered in (Program.cs). The hosted service is registered with the AddHostedService
extension method.
For more information on registering services, see Dependency injection in .NET.
[!INCLUDE run-app]
Let the application run for a bit to generate several execution count increments. You will see output similar to the following:
info: App.ScopedService.ScopedBackgroundService[0]
ScopedBackgroundService is running.
info: App.ScopedService.ScopedBackgroundService[0]
ScopedBackgroundService is working.
info: App.ScopedService.DefaultScopedProcessingService[0]
DefaultScopedProcessingService working, execution count: 1
info: Microsoft.Hosting.Lifetime[0]
Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
Content root path: .\scoped-service
info: App.ScopedService.DefaultScopedProcessingService[0]
DefaultScopedProcessingService working, execution count: 2
info: App.ScopedService.DefaultScopedProcessingService[0]
DefaultScopedProcessingService working, execution count: 3
info: App.ScopedService.DefaultScopedProcessingService[0]
DefaultScopedProcessingService working, execution count: 4
info: Microsoft.Hosting.Lifetime[0]
Application is shutting down...
info: App.ScopedService.ScopedBackgroundService[0]
ScopedBackgroundService is stopping.
[!INCLUDE stop-app]