Compartilhar via


Utilize serviços delimitados dentro de um BackgroundService

Quando você registra implementações de IHostedService usando qualquer um dos métodos de extensão de AddHostedService, o serviço é registrado como um singleton. Pode haver cenários em que você gostaria de contar com um serviço com escopo. Para obter mais informações, consulte Injeção de dependência no .NET: tempo de vida do serviço.

Neste tutorial, você aprenderá como:

Dica

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

Pré-requisitos

Criar um novo projeto

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

dotnet new worker --name <Project.Name>

Para obter mais informações sobre o novo comando do projeto de serviço de trabalho da CLI do .NET, confira dotnet new worker.

Dica

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

Criar serviços com escopo definido

Para usar serviços com escopo dentro de um BackgroundService, crie um escopo com a IServiceScopeFactory.CreateScope() API. Por padrão, nenhum escopo é criado para um serviço hospedado. O serviço em segundo plano com escopo contém a lógica da tarefa em segundo plano.

namespace App.ScopedService;

public interface IScopedProcessingService
{
    Task DoWorkAsync(CancellationToken stoppingToken);
}

A interface anterior define um único DoWorkAsync método. Crie uma implementação em uma nova classe chamada DefaultScopedProcessingService.cs:

namespace App.ScopedService;

public sealed class DefaultScopedProcessingService(
    ILogger<DefaultScopedProcessingService> logger) : IScopedProcessingService
{
    private readonly string _instanceId = Guid.NewGuid().ToString();

    public Task DoWorkAsync(CancellationToken stoppingToken)
    {
        logger.LogInformation(
            "{ServiceName} doing work, instance ID: {Id}",
            nameof(DefaultScopedProcessingService),
            _instanceId);

        return Task.CompletedTask;
    }
}
  • Um ILogger é injetado no serviço usando um construtor primário.
  • O DoWorkAsync método retorna um Task e aceita o CancellationToken.
    • O método registra o identificador de instância - o _instanceId é atribuído sempre que a classe é instanciada.

Reescrever a classe Worker

Substitua a classe existente Worker pelo seguinte código C# e renomeie o arquivo para 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);

        while (!stoppingToken.IsCancellationRequested)
        {
            using IServiceScope scope = serviceScopeFactory.CreateScope();

            IScopedProcessingService scopedProcessingService =
                scope.ServiceProvider.GetRequiredService<IScopedProcessingService>();

            await scopedProcessingService.DoWorkAsync(stoppingToken);

            await Task.Delay(10_000, stoppingToken);
        }
    }

    public override async Task StopAsync(CancellationToken stoppingToken)
    {
        logger.LogInformation(
            "{Name} is stopping.", ClassName);

        await base.StopAsync(stoppingToken);
    }
}

No código anterior, enquanto o stoppingToken não é cancelado, o IServiceScopeFactory é usado para criar um escopo. A partir do IServiceScope, o IScopedProcessingService é resolvido. O método DoWorkAsync é aguardado, e o stoppingToken é passado para o método. Por fim, a execução é atrasada por 10 segundos e o loop continua. Sempre que o método DoWorkAsync é chamado, uma nova instância de DefaultScopedProcessingService é criada e o identificador de instância é registrado.

Substitua o conteúdo do arquivo Program.cs pelo seguinte código C#:

using App.ScopedService;

HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Services.AddHostedService<ScopedBackgroundService>();
builder.Services.AddScoped<IScopedProcessingService, DefaultScopedProcessingService>();

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

Os serviços são registrados em (Program.cs). O serviço é registrado como hospedado com o método de extensão AddHostedService.

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

Verificar a funcionalidade do serviço

Para executar o aplicativo no Visual Studio, selecione F5 ou selecione a opção de menu Depuração>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 dotnet run da CLI do .NET, consulte.

Deixe o aplicativo executar por um tempo para gerar várias chamadas ao DoWorkAsync, registrando assim novos identificadores de instância. Você verá um resultado semelhante aos seguintes logs:

info: App.ScopedService.ScopedBackgroundService[0]
      ScopedBackgroundService is running.
info: App.ScopedService.DefaultScopedProcessingService[0]
      DefaultScopedProcessingService doing work, instance ID: 8986a86f-b444-4139-b9ea-587daae4a6dd
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 doing work, instance ID: 07a4a760-8e5a-4c0a-9e73-fcb2f93157d3
info: App.ScopedService.DefaultScopedProcessingService[0]
      DefaultScopedProcessingService doing work, instance ID: c847f432-acca-47ee-8720-1030859ce354
info: Microsoft.Hosting.Lifetime[0]
      Application is shutting down...
info: App.ScopedService.ScopedBackgroundService[0]
      ScopedBackgroundService is stopping.

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

Consulte também