3

.NET Worker Service

#.NET 5
Gabriel Faraday
Gabriel Faraday

Imagine que você precisa realizar um processamento em background (segundo plano), ou seja, um processamento que não é visível a um usuário final, um processamento de um arquivo grande, ou processar mensagens de um barramento de mensageria. Uma web API não é o melhor tipo de projeto para esta finalidade.


Quando tínhamos apenas o falecido .NET Framework (que descanse em paz!), tínhamos opções como Windows Service, ou até mesmo um Console App atenderia, com um while (true) infinito.


Mas e nos dias atuais, com o surgimento do .NET Core e atualmente com o .NET 5+???


A ideia é que talvez eu não queira estar no Windows! Talvez eu queira rodar de um container! Talvez eu queira estar na nuvem!


O Console App ainda está aí, mas cá entre nós, não é a forma mais elegante de resolver isso, não é mesmo?


Então como criar uma aplicação com essas características e de forma elegante?


Conhecendo o Worker Service do .NET


Quando você pensa em ASP.NET Core, provavelmente pensa em aplicações Web, incluindo MVC e web API. MVC Views e Razor Pages também permitem que você use código de backend para gerar UI de frontend com elementos HTML. O novo Blazor vai além, para permitir que o código .NET do lado do cliente seja executado em um navegador da web, usando WebAssembly. E a partir do ASP.NET Core 3.0, a Microsoft disponibilizou um novo template de projeto chamado Worker Service, que é parte da família ASP.NET!


Com ele as tarefas em background podem ser implementadas como serviços hospedados (Hosted Services), implementando a interface IHostedService.


E para criar um projeto inicial é muito simples, basta você ter a versão desejada do .NET (recomendo a versão mais atual, na data de escrita deste texto é o .NET 5 - https://dotnet.microsoft.com/download) e rodar o seguinte comando no seu cmd ou no shell:


dotnet new worker -n MeuWorker


Se você quiser conhecer mais sobre o .NET ou sobre como instalar ele em sua máquina, confira o curso de Introdução ao .NET que a DIO disponibiliza em seu portfólio de cursos, ou confira mais informações no meu canal do Youtube: https://www.youtube.com/c/GabrielFaraday


Seguindo o baile, ao rodar o comando acima, será criada uma pasta MeuWorker, com um projeto do tipo Worker Service dentro, com toda a estrutura mínima inicial para rodar a aplicação. Que é uma estrutura bem simples diga-se de passagem.


Arquivo MeuWorker.csproj


Diferente de uma web API, um projeto de Worker Service especifica no arquivo .csproj o Sdk:


<Project Sdk="Microsoft.NET.Sdk.Worker">


Na web API, para comparação, este é o Sdk:


<Project Sdk="Microsoft.NET.Sdk.Web">


Fora isso, no Worker Service é explicitamente referenciado o pacote:


<PackageReference Include="Microsoft.Extensions.Hosting" Version="5.0.0" />


Já para uma web API, este pacote é referenciado implicitamente na estrutura compartilhada, ou seja, uma referência de pacote explícita no .csproj não é necessária.


Apenas alguns comparativos para entendermos que Worker Service e web API são diferentes apesar de fazerem parte da família ASP.NET.


Arquivo Program.cs


Assim como em um web API ou mesmo um Console App, no Worker Service a execução da aplicação começa pelo método Main da classe Program.


  public class Program
  {
    public static void Main(string[] args)
    {
      CreateHostBuilder(args).Build().Run();
    }
 
    public static IHostBuilder CreateHostBuilder(string[] args) =>
      Host.CreateDefaultBuilder(args)
        .ConfigureServices((hostContext, services) =>
        {
          services.AddHostedService<Worker>();
        });
  }

 

O método Main irá criar, configurar e rodar um elemento self-hosted, assim como acontece para uma web API no .NET. A principal diferença é que uma web API vai configurar um host web, geralmente chamando um método ConfigureWebHostDefaults do host, mas isso não é importante nesse nosso contexto, apenas por curiosidade.

Porém, fora isso, é praticamente a mesma configuração inicial de uma web API, com exceção claro que no Worker Service, no método ConfigureServices é adiciona a classe Worker como um Hosted Service.


Arquivo Worker.cs


A classe Worker implementa a classe BackgroundService, que vem do namespace Microsoft.Extensions.Hosting.


  public class Worker : BackgroundService
  {
    private readonly ILogger<Worker> _logger;
 
    public Worker(ILogger<Worker> logger)
    {
      _logger = logger;
    }
 
    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
      while (!stoppingToken.IsCancellationRequested)
      {
        _logger.LogInformation($"Worker running at: {DateTime.Now}");
        await Task.Delay(1000, stoppingToken);
      }
    }
  }

 

É efetuado um override no método ExecuteAsync, e o código dentro dele será executado durante a execução do Worker.


O método recebe um CancellationToken como parâmetro. Este objeto tem uma propriedade booleana IsCancellationRequested que será true em situações que o Worker deverá ser finalizado, geralmente quando a thread de execução do worker finalizar por algum motivo. Ou seja, enquanto tudo estiver rodando normalmente, o worker irá funcionar, executando sua tarefa definida.


No código acima, será escrito um log indicando que o Worker está rodando na hora “x”. Então será dado um delay de 1 segundo e novamente será verificado se o IsCancellationRequested é diferente de true, e assim por diante, até que seja true.


Executando o Worker Service do .NET


Para executar a nossa aplicação via command line, basta executar o seguinte comando na pasta onde se encontra o arquivo .csproj:


dotnet run


A aplicação será compilada e inicializada. Assim que a aplicação sobe é iniciada sua execução. Na própria command line é possível visualizar os logs de execução:


Building...
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: /home/robin/git/MeuWorker
info: MeuWorker.Worker[0]
   Worker running at: 01/30/2021 17:35:14 -03:00
info: MeuWorker.Worker[0]
   Worker running at: 01/30/2021 17:35:15 -03:00
info: MeuWorker.Worker[0]
   Worker running at: 01/30/2021 17:35:16 -03:00
info: MeuWorker.Worker[0]
   Worker running at: 01/30/2021 17:35:17 -03:00
info: MeuWorker.Worker[0]
   Worker running at: 01/30/2021 17:35:18 -03:00
info: MeuWorker.Worker[0]
   Worker running at: 01/30/2021 17:35:19 -03:00
info: MeuWorker.Worker[0]
   Worker running at: 01/30/2021 17:35:20 -03:00
info: MeuWorker.Worker[0]
   Worker running at: 01/30/2021 17:35:21 -03:00
info: MeuWorker.Worker[0]
   Worker running at: 01/30/2021 17:35:22 -03:00
info: MeuWorker.Worker[0]
   Worker running at: 01/30/2021 17:35:23 -03:00
info: MeuWorker.Worker[0]
   Worker running at: 01/30/2021 17:35:24 -03:00
^Cinfo: Microsoft.Hosting.Lifetime[0]
   Application is shutting down...


Para interromper a execução da aplicação, basta pressionar Ctrl+C.


Recapitulando


O Worker Service é o “não tão novo” template .NET para aplicações que rodam em background e faz parte da família ASP.NET.


Sua criação e configuração inicial é bem parecida com a de uma web API, porém a forma como interagimos e até acompanhamos seu funcionamento é bem diferente.


O importante é conhecer ambos, Worker Service e web API, e saber em quais situações usar cada um.


1
38

Comentários (1)

1
Caio Negrão

Caio Negrão

12/02/2021 11:41

SHOW Professor!