Usar serviços com escopo em um BackgroundService

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

Neste tutorial, irá aprender a:

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ços com escopo

Para usar serviços com escopo em um , crie um BackgroundServiceescopo. Nenhum escopo é criado para um serviço hospedado por padrão. 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. Para definir a implementação padrão:

  • O serviço é assíncrono. O DoWorkAsync método retorna um Taskarquivo . Para fins de demonstração, espera-se um atraso de dez segundos no DoWorkAsync método.
  • Um ILogger é injetado no serviço.:
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);
        }
    }
}

O serviço hospedado cria um escopo para resolver o serviço em segundo plano com escopo para chamar seu DoWorkAsync método. DoWorkAsync Devolve um Task, que é aguardado em ExecuteAsync:

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);

        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);
    }
}

No código anterior, um escopo explícito é criado e a implementação é resolvida a IScopedProcessingService partir da fábrica de escopo do serviço de injeção de dependência. A instância de serviço resolvida tem escopo e seu DoWorkAsync método é aguardado.

Substitua o conteúdo do arquivo .cs programa modelo com o 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 estão registados no (Programa.cs). O serviço hospedado é registrado com o AddHostedService método de extensão.

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.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.

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