Dica Rápida: Executando tarefas em background com IHostedService
Tags: csharp, dotnet, aspnetcore
Published: 2020-10-22 12:46:08

Olá!

Este é mais um post da seção Dica Rápida, e hoje falaremos sobre um recurso bastante útil, mas aparentemente pouco conhecido, do Asp.Net Core: o Hosted Service.

Este recurso é expresso pela interface [IHostedService](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/hosted-services?view=aspnetcore-3.1&tabs=visual-studio) (em inglês) que permite à uma implementação reagir aos eventos de inicialização e encerramento do host da aplicação, permitindo que operações sejam realizadas, por exemplo, quando a aplicação é iniciada.

Antes de mais nada, vamos conhecer a interface:

```c#
namespace Microsoft.Extensions.Hosting
{
    public interface IHostedService
    {
        Task StartAsync(CancellationToken cancellationToken);
        Task StopAsync(CancellationToken cancellationToken);
    }
}    
```

Simples. Não? Vejamos uma implementação bem simples da interface:

```c#
namespace Lab.HostedService
{
	public class MyHostedService()
	{
        public Task StartAsync(CancellationToken cancellationToken)
        {
            Console.WriteLine("Host iniciado.");
            return Task.CompletedTask;
        }
        
        public Task StopAsync(CancellationToken cancellationToken)
        {
            Console.WriteLine("Host encerrado.");
            return Task.CompletedTask;
        }
	}
}
```

Uma vez implementada a interface com alguma operação que desejemos executar ao iniciar a aplicação, que inclusive pode ser uma tarefa de longa duração que durará pelo tempo de vida da aplicação, tudo o que precisamos fazer é incluí-la no pipeline de criação da aplicação, e há duas formas para fazê-lo como podemos ver nos dois exemplos abaixo.

Primeiro, a inclusão de um serviço que apenas reagirá à inicialização ou encerramento de nosso host:

```c#
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

namespace Lab.HostedService
{
	public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(builder =>
                    builder.UseStartup<Startup>()
                )
                .ConfigureServices(services =>
                    services.AddHostedService<MyHostedService>()
                );
    }
}
```

Em seguida, um exemplo onde um serviço poderia ser invocado em outros pontos da aplicação se necessário:

```c#
namespace Lab.HostedService
{
	public class Startup
    {
	    ...
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddSingleton<MyHostedService>();
            services.AddHostedService(services => services.GetService<MyHostedService>());
        }
        ...
	}
}
```

E pronto! 

Um detalhe interessante é que há uma implementação padrão para esta interface, também provida pelo Asp.Net Core, a classe base `BackgroundService`. Ela nos permite implementar tarefas de longa duração de forma mais simples, trazendo o método `ExecuteAsync` que deverá conter nossaa lógica, como a seguir.

```c#
namespace Lab.HostedService
{
	public class MyBackgroundService
	{
		protected override async Task StartAsync(CancellationToken cancellationToken)
         {
			Console.WriteLine("Host iniciado.");
             return Task.CompletedTask;
         }

		protected override Task StopAsync(CancellationToken cancellationToken)
         {
			Console.WriteLine("Host encerrado.");
			return Task.CompletedTask;
		}

         protected override async Task ExecuteAsync(CancellationToken stoppingToken)
         {
		   while(!stoppingToken.IsCancellationRequested)
            {
            	//Realiza alguma operação, como tentar ler uma fila ou monitorar uma pasta por novos arquivos
            	await Task.Delay(1_000);
            }
         }
	}
}
```

E assim temos duas formas providas pelo Asp.Net Core para executar operações tão logo nosso host esteja pronto para executá-las, ou em processo de encerramento.

Para maiores informações sobre outras formas de implementar a interface `IHostedService`, recomendo esta [documentação](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/hosted-services?view=aspnetcore-3.1&tabs=visual-studio) (em inglês).

Espero que tenha gostado! Se gostou, me deixe saber pelos indicadores. Se tiver alguma dúvida, deixe um comentário que responderei assim que puder.

Até a próxima!