Criando um Daemon com .NET Core (Parte 1)
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.
- 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
- 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
- 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>
- 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>
- Salve o
.csproj file
- De volta ao CLI, instale as dependências
dotnet restore
- 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;
- Mude a assinatura do método para ser assíncroníncro. Main
public static async Task Main(string[] args)
- 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();
- Agora salve o arquivo.Program.cs
- Crie um novo arquivo chamado . Este é o arquivo de classe que define seu serviço.DaemonService.cs
- 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....");
}
}
}
- Salvar.DaemonService.cs
- 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; }
}
}
- Agora, tudo está pronto para compilar. De volta ao CLI, construa o aplicativo
dotnet build
- 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
- 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