Uso de servicios con ámbito en BackgroundService
Al registrar implementaciones de IHostedService mediante cualquiera de los métodos de extensión AddHostedService, el servicio se registra como singleton. Puede haber escenarios en los que quiera confiar en un servicio con ámbito. Para obtener más información, vea Inserción de dependencias en .NET: duraciones del servicio.
En este tutorial aprenderá a:
- Resolver las dependencias con ámbito en un singleton BackgroundService.
- Delegar trabajo en un servicio con ámbito.
- Implementar un
override
de BackgroundService.StopAsync(CancellationToken).
Sugerencia
Todo el ejemplo de "Trabajos en .NET" está disponible en el Explorador de ejemplos para su descarga. Para obtener más información, consulte Examinación de ejemplos de código: Trabajos en .NET.
Requisitos previos
- El SDK de .NET 8.0 o posterior
- Un entorno de desarrollo integrado (IDE) de .NET
- No dude en usar Visual Studio
Creación de un nuevo proyecto
Para crear un proyecto de Worker Service con Visual Studio, seleccione Archivo>Nuevo>Proyecto... . En el cuadro de diálogo Crear un proyecto, busque "Worker Service" y seleccione la plantilla Worker Service. Si prefiere usar la CLI de .NET, abra su terminal favorito en un directorio de trabajo. Ejecute el comando dotnet new
y reemplace <Project.Name>
por el nombre del proyecto deseado.
dotnet new worker --name <Project.Name>
Para más información sobre el comando del nuevo proyecto de Worker Service de la CLI de .NET, vea dotnet new worker.
Sugerencia
Si usa Visual Studio Code, puede ejecutar comandos de la CLI de .NET desde el terminal integrado. Para más información, vea Visual Studio Code: terminal integrado.
Creación de servicios con ámbito
Para usar servicios con ámbito en un elemento BackgroundService
, cree un ámbito. No se crean ámbitos de forma predeterminada para los servicios hospedados. El servicio de tareas en segundo plano con ámbito contiene la lógica de la tarea en segundo plano.
namespace App.ScopedService;
public interface IScopedProcessingService
{
Task DoWorkAsync(CancellationToken stoppingToken);
}
La interfaz anterior define un único método DoWorkAsync
. Para definir la implementación predeterminada:
- El servicio es asincrónico. El método
DoWorkAsync
devuelve un objetoTask
. Para fines de demostración, se espera un retraso de diez segundos en el métodoDoWorkAsync
. - ILogger se inserta en el servicio:
namespace App.ScopedService;
public sealed class DefaultScopedProcessingService(
ILogger<DefaultScopedProcessingService> logger) : IScopedProcessingService
{
private int _executionCount;
public async Task DoWorkAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
++ _executionCount;
logger.LogInformation(
"{ServiceName} working, execution count: {Count}",
nameof(DefaultScopedProcessingService),
_executionCount);
await Task.Delay(10_000, stoppingToken);
}
}
}
El servicio hospedado crea un ámbito con el fin de resolver el servicio de tareas en segundo plano con ámbito para llamar a su método DoWorkAsync
. DoWorkAsync
devuelve Task
, que se espera en ExecuteAsync
:
Reescritura de la clase Worker
Reemplace la clase Worker
por el siguiente código de C# y cambie el nombre del archivo a ScopedBackgroundService.cs:
namespace App.ScopedService;
public sealed class ScopedBackgroundService(
IServiceScopeFactory serviceScopeFactory,
ILogger<ScopedBackgroundService> logger) : BackgroundService
{
private const string ClassName = nameof(ScopedBackgroundService);
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
logger.LogInformation(
"{Name} is running.", ClassName);
await DoWorkAsync(stoppingToken);
}
private async Task DoWorkAsync(CancellationToken stoppingToken)
{
logger.LogInformation(
"{Name} is working.", ClassName);
using (IServiceScope scope = serviceScopeFactory.CreateScope())
{
IScopedProcessingService scopedProcessingService =
scope.ServiceProvider.GetRequiredService<IScopedProcessingService>();
await scopedProcessingService.DoWorkAsync(stoppingToken);
}
}
public override async Task StopAsync(CancellationToken stoppingToken)
{
logger.LogInformation(
"{Name} is stopping.", ClassName);
await base.StopAsync(stoppingToken);
}
}
En el código anterior, se crea un ámbito explícito y la implementación del IScopedProcessingService
se resuelve desde el generador de ámbitos del servicio de inserción de dependencias. La instancia de servicio resuelta está limitada y se espera su método DoWorkAsync
.
Reemplace el contenido del archivo Program.cs de la plantilla por el siguiente código de C#:
using App.ScopedService;
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Services.AddHostedService<ScopedBackgroundService>();
builder.Services.AddScoped<IScopedProcessingService, DefaultScopedProcessingService>();
IHost host = builder.Build();
host.Run();
Los servicios se registran en (Program.cs). El servicio hospedado se registra con el método de extensión AddHostedService
.
Para obtener más información sobre el registro de servicios, consulte Inserción de dependencias en .NET.
Comprobación de la funcionalidad del servicio
Para ejecutar la aplicación desde Visual Studio, seleccione F5 o la opción de menú Depurar>Iniciar depuración. Si usa la CLI de .NET, ejecute el comando dotnet run
desde el directorio de trabajo:
dotnet run
Para más información sobre el comando run de la CLI de .NET, consulte dotnet run.
Deje que la aplicación se ejecute durante un poco para generar varios incrementos de recuento de ejecuciones. Verá un resultado similar al siguiente:
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.
Si ejecuta la aplicación desde dentro Visual Studio, seleccione Depurar>Detener depuración... . Como alternativa, seleccione Ctrl + C en la ventana de consola para indicar la cancelación.