Partilhar via


Implementar a IHostedService interface

Quando você precisa de controle finito além do fornecido BackgroundService, você pode implementar o seu próprio IHostedService. A IHostedService interface é a base para todos os serviços de longa execução no .NET. As implementações personalizadas são registradas com o AddHostedService<THostedService>(IServiceCollection) método de extensão.

Neste tutorial, irá aprender a:

  • Implemente o IHostedService, e IAsyncDisposable interfaces.
  • Crie um serviço baseado em temporizador.
  • Registre a implementação personalizada com injeção de dependência e registro.

Gorjeta

Todo o código-fonte de exemplo "Workers in .NET" está disponível no Navegador de Amostras para download. Para obter mais informações, consulte Procurar exemplos de código: Trabalhadores no .NET.

Pré-requisitos

Criar um novo projeto

Para criar um novo projeto do Serviço de Trabalho com o Visual Studio, selecione Arquivo>Novo>Projeto....Na caixa de diálogo Criar um novo projeto, procure por "Serviço de Trabalho" e selecione Modelo de Serviço de Trabalhador. Se você preferir usar a CLI do .NET, abra seu terminal favorito em um diretório de trabalho. Execute o comando e substitua o dotnet new pelo nome do <Project.Name> projeto desejado.

dotnet new worker --name <Project.Name>

Para obter mais informações sobre o comando .NET CLI new worker service project, consulte dotnet new worker.

Gorjeta

Se você estiver usando o Visual Studio Code, poderá executar comandos da CLI do .NET a partir do terminal integrado. Para obter mais informações, consulte Visual Studio Code: Integrated Terminal.

Criar serviço de temporizador

O serviço em segundo plano baseado em temporizador faz uso da System.Threading.Timer classe. O temporizador aciona o DoWork método. O temporizador é desativado IHostLifetime.StopAsync(CancellationToken) e eliminado quando o contentor de serviço é eliminado em IAsyncDisposable.DisposeAsync():

Substitua o conteúdo do Worker modelo pelo seguinte código C# e renomeie o arquivo para 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

O Worker foi uma subclasse de BackgroundService. Agora, o TimerService implementa o IHostedService, e IAsyncDisposable interfaces.

O TimerService é sealed, e cascata a DisposeAsync chamada de sua _timer instância. Para obter mais informações sobre o "padrão de descarte em cascata", consulte Implementar um DisposeAsync método.

Quando StartAsync é chamado, o temporizador é instanciado, iniciando assim o temporizador.

Gorjeta

O Timer não espera que as execuções anteriores terminem, portanto, a abordagem mostrada DoWork pode não ser adequada para todos os cenários. Interlocked.Increment é usado para incrementar o contador de execução como uma operação atômica, o que garante que vários threads não sejam atualizados _executionCount simultaneamente.

Substitua o conteúdo existente Program pelo seguinte código C#:

using App.TimerHostedService;

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

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

O serviço é registrado em (Programa.cs) com o método de AddHostedService extensão. Este é o mesmo método de extensão que você usa ao registrar BackgroundService subclasses, pois ambas implementam a IHostedService interface.

Para obter mais informações sobre como registrar serviços, consulte Injeção de dependência no .NET.

Verificar a funcionalidade do serviço

Para executar o aplicativo do Visual Studio, selecione F5 ou selecione a opção de menu Depurar Iniciar Depuração>. Se você estiver usando a CLI do .NET, execute o dotnet run comando no diretório de trabalho:

dotnet run

Para obter mais informações sobre o comando .NET CLI run, consulte dotnet run.

Deixe o aplicativo ser executado por um pouco para gerar vários incrementos de contagem de execução. Você verá uma saída semelhante à seguinte:

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.

Se estiver executando o aplicativo de dentro do Visual Studio, selecione Depurar Parar Depuração>.... Como alternativa, selecione Ctrl + C na janela do console para sinalizar o cancelamento.

Consulte também

Existem vários tutoriais relacionados a considerar: