Compartir vía


Implementación de la interfaz IHostedService

Cuando necesite un control finito más allá del BackgroundService proporcionado, puede implementar su propio IHostedService. La interfaz IHostedService es la base de todos los servicios de larga duración en .NET. Las implementaciones personalizadas se registran con el método AddHostedService<THostedService>(IServiceCollection) de extensión.

En este tutorial aprenderá a:

  • Implemente las interfaces IHostedService y IAsyncDisposable.
  • Cree un servicio basado en temporizador.
  • Registre la aplicación personalizada con inserción de dependencias y registro.

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

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 un servicio de temporizador

El servicio en segundo plano basado en temporizador usa la clase System.Threading.Timer. El temporizador desencadena el método DoWork. El temporizador está deshabilitado en IHostLifetime.StopAsync(CancellationToken) y se desecha cuando el contenedor de servicios se elimina en IAsyncDisposable.DisposeAsync():

Reemplace el contenido de Worker de la plantilla por el siguiente código de C# y cambie el nombre del archivo a TimerService.cs:

namespace App.TimerHostedService;

public sealed class TimerService(ILogger<TimerService> logger) : IHostedService, IAsyncDisposable
{
    private readonly Task _completedTask = Task.CompletedTask;
    private int _executionCount = 0;
    private Timer? _timer;

    public Task StartAsync(CancellationToken stoppingToken)
    {
        logger.LogInformation("{Service} is running.", nameof(TimerHostedService));
        _timer = new Timer(DoWork, null, TimeSpan.Zero, TimeSpan.FromSeconds(5));

        return _completedTask;
    }

    private void DoWork(object? state)
    {
        int count = Interlocked.Increment(ref _executionCount);

        logger.LogInformation(
            "{Service} is working, execution count: {Count:#,0}",
            nameof(TimerHostedService),
            count);
    }

    public Task StopAsync(CancellationToken stoppingToken)
    {
        logger.LogInformation(
            "{Service} is stopping.", nameof(TimerHostedService));

        _timer?.Change(Timeout.Infinite, 0);

        return _completedTask;
    }

    public async ValueTask DisposeAsync()
    {
        if (_timer is IAsyncDisposable timer)
        {
            await timer.DisposeAsync();
        }

        _timer = null;
    }
}

Importante

Worker era una subclase de BackgroundService. Ahora, TimerService implementa las interfaces IHostedService y IAsyncDisposable.

TimerService es sealed y en llamada en cascada a DisposeAsync desde su instancia _timer. Para obtener más información sobre el patrón de eliminación en cascada, vea Implementar un métodoDisposeAsync.

Cuando se llama a StartAsync, se crea una instancia del temporizador, iniciando así el temporizador.

Sugerencia

Timer no espera a que finalicen las ejecuciones anteriores de DoWork, por lo que es posible que el enfoque mostrado no sea adecuado para todos los escenarios. Interlocked.Increment se usa para incrementar el contador de ejecución como una operación atómica, lo que garantiza que varios subprocesos no actualicen _executionCount simultáneamente.

Reemplace el contenido Program por el siguiente código de C#:

using App.TimerHostedService;

HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Services.AddHostedService<TimerService>();

IHost host = builder.Build();
host.Run();

El servicio se registra en (Program.cs) con el método de extensión AddHostedService. Este es el mismo método de extensión que se usa al registrar subclases BackgroundService, ya que ambos implementan la interfaz IHostedService.

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.TimerHostedService.TimerService[0]
      TimerHostedService is running.
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: .\timer-service
info: App.TimerHostedService.TimerService[0]
      TimerHostedService is working, execution count: 1
info: App.TimerHostedService.TimerService[0]
      TimerHostedService is working, execution count: 2
info: App.TimerHostedService.TimerService[0]
      TimerHostedService is working, execution count: 3
info: App.TimerHostedService.TimerService[0]
      TimerHostedService is working, execution count: 4
info: Microsoft.Hosting.Lifetime[0]
      Application is shutting down...
info: App.TimerHostedService.TimerService[0]
      TimerHostedService 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.

Vea también

Puede consultar diferentes tutoriales relacionados: