Daemons são tão essenciais para os servidores quanto cafeína e pizza são para os desenvolvedores. Os executáveis são executados como serviços em um servidor esperando para receber entrada geralmente de uma chamada de rede, e respondem a ela fornecendo algo de volta para o usuário que o chamou. .NET Core é a venerável pilha de desenvolvimento multiplataforma para Linux, Mac e Windows. Até agora, o .NET Core realmente não teve uma boa história para escrever daemons, mas com a introdução de métodos principais assíncronsos, GenericHosts e RunConsoleAsync isso não só é possível, mas incrivelmente elegante em sua implementação. Segue os padrões de nome que ASP.NET desenvolvedores do Core passaram a amar. A principal diferença, porém, é que, em ASP.NET Core, o serviço Web Host é fornecido a você como um serviço e você escreve controladores para lidar com solicitações. Com um Host Genérico, cabe a você implementar o host.

Neste pequeno tutorial, vamos passar por cima do básico de escrever um daemon usando .NET Core e um Host Genérico.

Baixe o Projeto Completo aqui.

  1. Crie um aplicativo. O aplicativo básico do console para o modelo .NET Core é pouco mais do que um aplicativo Hello World. No entanto, não é preciso muito para transformar isso em uma aplicação estilo daemon.
dotnet new console --name mydaemon
  1. Para fazer este aplicativo funcionar como um daemon, há algumas coisas que precisamos mudar no arquivo, então o arquivo myadaemon.csproj em um editor de texto..csproj
  2. Este arquivo de projeto é um arquivo XML que contém um conjunto básico de seções. Precisamos adicionar uma seção para dizer ao compilador para usar C# 7.1. Isso permite que seu método seja assíncroto, o que não é permitido na versão padrão de C#, 7.0. Adicione o trecho de código a seguir antes da tag de fechamento. Main</Project>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
 <LangVersion>7.1</LangVersion>
</PropertyGroup>

  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
  <LangVersion>7.1</LangVersion>
</PropertyGroup>   
  1. Agora, precisamos adicionar algumas dependências para fazer o aplicativo funcionar. Estas são todas as extensões que podem ser usadas em aplicativos de console, mas também podem ser usadas em aplicativos web. Adicione o trecho de código a seguir antes da tag de fechamento. Aqui, você está adicionando dependências para a linha de comando e configuração do ambiente, a capacidade de fazer login no console e adicionando dependências para fazer a injeção de dependência para o Host Genérico. </Project>
<ItemGroup>
 <PackageReference Include="Microsoft.Extensions.Configuration" Version="2.1.1" />
 <PackageReference Include="Microsoft.Extensions.Configuration.CommandLine" Version="2.1.1" />
 <PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="2.1.1" />
 <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="2.1.1" />
 <PackageReference Include="Microsoft.Extensions.Hosting" Version="2.1.1" />
 <PackageReference Include="Microsoft.Extensions.Logging" Version="2.1.1" />
 <PackageReference Include="Microsoft.Extensions.Logging.Configuration" Version="2.1.1" />
 <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="2.1.1" />
 <PackageReference Include="Microsoft.Extensions.Options" Version="2.1.1" />
 <PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="2.1.1" />
</ItemGroup>
  1. Salve o .csproj file
  2. De volta ao CLI, instale as dependências
dotnet restore
  1. Agora, edite o arquivo. Adicione os seguintes espaços de nome à parte superior do arquivo: Program.cs
using System.Threading.Tasks;
 using Microsoft.Extensions.Configuration;
 using Microsoft.Extensions.DependencyInjection;
 using Microsoft.Extensions.Hosting;
 using Microsoft.Extensions.Logging;
  1. Mude a assinatura do método para ser assíncroníncro. Main
 public static async Task Main(string[] args)
  1. Substitua o código no método principal pelo seguinte trecho de código. Este código está fiando a configuração do daemon usando a classe. O construtor informa ao construtor de onde obter informações de configuração, e neste caso estamos usando a linha de comando e o ambiente. diz ao construtor quais serviços usar e como instanciar eles. No caso de um daemon, é mais provável que seu serviço seja um Singleton, o que significa que há apenas uma instância do serviço durante toda a duração do aplicativo. Ele também adiciona o objeto POCO configuração aos serviços para injeção de dependência. Isso implementa a interface no .NET Core, que pode ter um tipo que tentará vincular parâmetros CLI e variáveis de ambiente com base no nome de campo. fio para cima registro do console usando a interface. O molho secreto para fazer o programa funcionar como um daemon é o método. Este método coloca o aplicativo em um estado de espera que está procurando ou sem consumir CPU. Enquanto o aplicativo está funcionando, seu serviço também está definido pelo método.
HostBuilderConfigureAppConfigurationConfigureServicesIOptionConfigureLoggingILoggerRunConsoleAsyncCtrl + CCtrl + BreakConfigureServices
 var builder = new HostBuilder()
     .ConfigureAppConfiguration((hostingContext, config) =>
     {
         config.AddEnvironmentVariables();

         if (args != null)
         {
             config.AddCommandLine(args);
         }
     })
     .ConfigureServices((hostContext, services) =>
     {
         services.AddOptions();
         services.Configure<DaemonConfig>(hostContext.Configuration.GetSection("Daemon"));

         services.AddSingleton<IHostedService, DaemonService>();
     })
     .ConfigureLogging((hostingContext, logging) => {
         logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
         logging.AddConsole();
     });

 await builder.RunConsoleAsync();
  1. Agora salve o arquivo.Program.cs
  2. Crie um novo arquivo chamado . Este é o arquivo de classe que define seu serviço.DaemonService.cs
  3. Cole o seguinte código no arquivo. Esta classe implementa e . A interface é usada pelo construtor para criar um serviço que seja “hospedado” no aplicativo do console. Tem dois métodos básicos: e que são chamados quando o serviço é iniciado e interrompido, respectivamente. Esses métodos permitem uma graciosa inicialização e desligamento do serviço. Se um serviço for implementado, o método será chamado. Esta é uma gentileza para quaisquer etapas finais de limpeza necessárias depois que é chamado. O construtor aceita uma série de interfaces como parâmetros, que são resolvidas pela injeção de dependência incorporada ao construtor. E são alguns dos tipos padrão de dependências que muitos aplicativos têm.
IHostedServiceIDisposableIHostedServiceProgram.csStartAsyncStopAsyncIDisposableDisposeStopAsyncloggerconfig
 using System;
 using System.Threading;
 using System.Threading.Tasks;
 using Microsoft.Extensions.Hosting;
 using Microsoft.Extensions.Logging;
 using Microsoft.Extensions.Options;

 namespace mydaemon
 {

     public class DaemonService : IHostedService, IDisposable
     {
         private readonly ILogger _logger;
         private readonly IOptions<DaemonConfig> _config;
         public DaemonService(ILogger<DaemonService> logger, IOptions<DaemonConfig> config)
         {
             _logger = logger;
             _config = config;
         }

         public Task StartAsync(CancellationToken cancellationToken)
         {
             _logger.LogInformation("Starting daemon: " + _config.Value.DaemonName);
             return Task.CompletedTask;
         }

         public Task StopAsync(CancellationToken cancellationToken)
         {
             _logger.LogInformation("Stopping daemon.");
             return Task.CompletedTask;
         }

         public void Dispose()
         {
             _logger.LogInformation("Disposing....");

         }
     }
 }
  1. Salvar.DaemonService.cs
  2. Agora, crie um arquivo chamado e cole no código a seguir. Esta é apenas uma classe POCO a que a configuração tentará vincular propriedades. Salve o arquivo quando terminar. DaemonConfig.cs
using System;

 namespace mydaemon
 {
     public class DaemonConfig 
     {
         public string DaemonName { get; set; } 
     }
 }
  1. Agora, tudo está pronto para compilar. De volta ao CLI, construa o aplicativo
 dotnet build
  1. Agora você pode executar o aplicativo
dotnet run --Daemon:DaemonName="Cool Daemon"

A saída será semelhante à seguinte:

Application started. Press Ctrl+C to shut down.
 infoHosting environment: Production
 Content root path: D:\source\dotnet-daemon\daemon\bin\Debug\netcoreapp2.1\
 : daemon.DaemonService[0]
       Starting daemon: Cool Daemon
      
  1. O aplicativo está sendo executado agora e você pode usar para pará-lo.Ctrl + C

Conclusão

Este tutorial demonstra como enquadrar um daemon do núcleo .NET usando alguns dos recursos mais novos disponíveis no .NET, como o Host Genérico, métodos assíncronsos e para manter o aplicativo do console funcionando. Além disso, essa estrutura torna o código testável e mantenedor usando padrões que são familiares àqueles que usam ASP.NET Core.MainRunConsoleAsync

Na Parte 2, usaremos isso para realmente fazer um daemon útil: um .NET Core MQTT Broker.


Autor: Blaize Stewart

Artigo Original