Um Worker Service no .NET é uma aplicação que roda em segundo plano, projetada para executar tarefas contínuas ou agendadas, sem a necessidade de interação direta com o usuário. Isso torna o Worker Service uma excelente opção para tarefas como processamento de dados, envio de e-mails, ou integração com filas de mensagens, especialmente em projetos que já possuem uma API existente.
Uma das grandes vantagens é que você pode implementar um Worker Service dentro de um projeto de API já existente, sem a necessidade de criar um novo projeto separado. Isso facilita o gerenciamento e a manutenção do código, além de permitir a reutilização de serviços e configurações da API.
Implementando um Worker Service em um projeto de API existente
O Worker Service pode ser implementado dentro da estrutura do projeto existente, por exemplo, em uma nova pasta chamada “Workers”. Essa abordagem centraliza o código e simplifica a manutenção.
Após criar uma pasta no local desejado, crie a classe. Para o nosso exemplo, eu criei uma classe chamada “ProcesamentoPedidosWorker.cs” dentro dessa pasta, simulando um serviço que realiza o processamento de pedidos de um e-commerce:
public class ProcesamentoPedidosWorker : BackgroundService
{
private readonly ILogger _logger;
public ProcesamentoPedidosWorker(ILogger logger)
{
_logger = logger;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
_logger.LogInformation("Processando pedidos”);
await Task.Delay(5000, stoppingToken);
}
}
}
Em nosso exemplo acima, a classe “ProcesamentoPedidosWorker”, herda da classe “BackgroundService”, uma abstração fornecida pelo .NET para facilitar a criação de serviços de segundo plano. No construtor de “ProcesamentoPedidosWorker”, o serviço de log (ILogger) é injetado para registrar informações, erros ou outras mensagens durante a execução do Worker. A injeção de dependência permite que o Worker use os serviços registrados no container da aplicação (como repositórios, serviços de e-mail, etc.). Neste caso, estamos injetando um logger para registrar logs da execução.
O método mais importante em um Worker Service é o “ExecuteAsync”, que contém a lógica principal que será executada em segundo plano. Nele criamos um loop “while” que garante que o Worker continue executando enquanto o serviço não for cancelado. O “stoppingToken” é um token de cancelamento que sinaliza quando o serviço deve parar (como ao desligar a aplicação).
Após isso, usamos o “ILogger” para registrar uma mensagem a cada execução. Por fim, o método “Task.Delay(5000)” cria uma pausa de 5 segundos entre cada ciclo de execução, simulando a execução de uma tarefa periódica. O “stoppingToken” é passado para permitir que a tarefa seja interrompida caso o Worker seja cancelado.
Registre o Worker no Program.cs
Para que o Worker Service seja executado em conjunto com a sua API, você precisa registrá-lo no “Program.cs”.
No arquivo “Program.cs”, adicione o registro do serviço:
builder.Services.AddHostedService();
No exemplo acima, utilizamos o método “AddHostedService” para registrar o Worker Service na coleção de serviços da aplicação. A classe “ProcesamentoPedidosWorker” é passada como o tipo do serviço, indicando ao .NET que essa classe será executada em segundo plano enquanto a API estiver ativa. Isso permite que o “ProcesamentoPedidosWorker” execute suas tarefas paralelamente, sem bloquear as operações da API, facilitando a implementação de processos contínuos ou agendados no seu projeto.
Injeção de Dependências no Worker Service
Assim como acontece nas APIs, o Worker Service pode aproveitar o ServiceProvider para a injeção de dependências. Isso permite o uso de serviços e repositórios que já existem no seu projeto, facilitando a integração.
No exemplo abaixo, vamos supor que você tenha um serviço “IEmailService” que envia e-mails, e deseja utilizá-lo no Worker:
public interface IEmailService
{
Task SendEmailAsync(string to, string subject, string body);
}
public class EmailService : IEmailService
{
public Task SendEmailAsync(string to, string subject, string body)
{
Console.WriteLine($"Enviando e-mail para {to}");
//Implementação do envio de e-mail.
return Task.CompletedTask;
}
}
Agora, no seu Worker, você pode injetar esse serviço e utilizá-lo para enviar e-mails:
public class ProcesamentoPedidosWorker: BackgroundService
{
private readonly ILogger _logger;
private readonly IEmailService _emailService;
public ProcesamentoPedidosWorker(ILogger logger, IEmailService emailService)
{
_logger = logger;
_emailService = emailService;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
_logger.LogInformation("Processando pedidos”);
await _emailService.SendEmailAsync("cliente@exemplo.com", "Pedido aprovado", "Seu pedido foi aprovado!");
await Task.Delay(5000, stoppingToken);
}
}
}
E não se esqueça de registrar o serviço “IEmailService” no “Program.cs”:
builder.Services.AddSingleton();
Dessa forma, o serviço de e-mail será usado pelo Worker sempre que ele for executado.
Acelere a sua carreira conosco!
Se você é Desenvolvedor .NET Júnior e quer acelerar sua carreira até nível Pleno com salário de R$7k+, ou mesmo busca a primeira vaga, conheça a Mentoria .NET Start: Clique aquiSe é Desenvolvedor .NET Pleno ou Sênior e quer virar referência técnica em sua equipe e mercado, com salário de R$10k+, conheça a Mentoria .NET Expert: Clique aqui
Conclusão
A integração de um Worker Service em um projeto de API existente no .NET oferece uma solução eficiente e centralizada para tarefas em segundo plano. O Worker Service pode ser facilmente adicionado em uma pasta do projeto, aproveitando toda a infraestrutura existente, como injeção de dependências e configurações. Além disso, ele é ideal para cenários como tarefas agendadas, monitoramento de serviços e processamento de dados.
Esse recurso permite criar uma arquitetura mais robusta, escalável e modular, facilitando o gerenciamento de processos de segundo plano na aplicação e proporcionando uma implementação eficiente e organizada para atender as necessidades específicas do sistema.