Gerenciamento de Serviços via Linha de Comando
Para hospedar uma aplicação Worker do .NET como um Serviço do Windows nativo, é fundamental compreender o utilitário sc.exe (Service Control). Esta ferramenta nativa permite criar, configurar, iniciar e remover serviços diretamente pelo prompt de comendo.
Scripts de Instalação e Remoção
Abaixo estão exemplos de comandos para automatizar o ciclo de vida do serviço. Certifique-se de executar o terminal com privilégios administrativos.
:: install_service.bat
@echo off
set SVC_NAME=DataSyncWorker
set SVC_PATH="C:\Applications\DataSync\bin\Release\net8.0\DataSyncWorker.exe"
set SVC_DESC="Serviço de sincronização de dados em segundo plano"
sc.exe create %SVC_NAME% binPath= %SVC_PATH% start= auto
sc.exe description %SVC_NAME% %SVC_DESC%
sc.exe start %SVC_NAME%
pause
:: uninstall_service.bat
@echo off
set SVC_NAME=DataSyncWorker
sc.exe stop %SVC_NAME%
sc.exe delete %SVC_NAME%
pause
Comandos Individuais do sc.exe
Caso prefira executar as operações manualmente, utilize a seguinte sintaxe:
- Criar:
sc.exe create NomeDoServico binPath= "C:\caminho\para\executavel.exe" - Iniciar:
sc.exe start NomeDoServico - Parar:
sc.exe stop NomeDoServico - Remover:
sc.exe delete NomeDoServico - Alterar Descrição:
sc.exe description NomeDoServico "Nova descrição detalhada" - Modificar Tipo de Inicialização:
sc.exe config NomeDoServico start= demand(Opções:auto,demand,disabled)
Implementação no Código .NET
O processo de adaptação de um projeto Worker para rodar como um serviço Windows exige a adição de pacotes específicos e pequenas alterações na configuração do host.
1. Referência de Pacotes
Adicione as dependências necessárias ao seu arquivo .csproj:
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="8.0.0" />
</ItemGroup>
2. Configuração do Host (Program.cs)
Configure o construtor do host para utilizar o provedor de serviços do Windows. Isso permite que o aplicativo responda corretamente aos sinais de inicio e parada do SCM (Service Control Manager).
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace WindowsServiceHostingDemo
{
public class Program
{
public static void Main(string[] arguments)
{
var host = Host.CreateDefaultBuilder(arguments)
.UseWindowsService(options =>
{
options.ServiceName = "DataSyncWorker";
})
.ConfigureServices((context, collection) =>
{
collection.AddHostedService<TaskExecutor>();
})
.Build();
host.Run();
}
}
}
3. Lógica do Worker (TaskExecutor.cs)
A classe de execução deve herdar de BackgroundService. Neste exemplo, a lógica foi refactorada para utilizar operações de arquivo assíncronas e garantir a criação do diretório de logs de forma segura.
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
namespace WindowsServiceHostingDemo
{
public class TaskExecutor : BackgroundService
{
private readonly ILogger<TaskExecutor> _logger;
private readonly string _traceFilePath;
public TaskExecutor(ILogger<TaskExecutor> logger)
{
_logger = logger;
_traceFilePath = Path.Combine(AppContext.BaseDirectory, "Traces", "activity.log");
var directory = Path.GetDirectoryName(_traceFilePath);
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory!);
}
}
public override async Task StartAsync(CancellationToken cancellationToken)
{
await RegisterEventAsync("Service Initialized");
await base.StartAsync(cancellationToken);
}
public override async Task StopAsync(CancellationToken cancellationToken)
{
await RegisterEventAsync("Service Terminated");
await base.StopAsync(cancellationToken);
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
_logger.LogInformation("Background task executing at: {Time}", DateTime.UtcNow);
await RegisterEventAsync($"Execution cycle completed at {DateTime.UtcNow}");
await Task.Delay(TimeSpan.FromSeconds(5), stoppingToken);
}
}
private async Task RegisterEventAsync(string message)
{
var logEntry = $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] {message}{Environment.NewLine}";
await File.AppendAllTextAsync(_traceFilePath, logEntry);
}
}
}
Considerações de Implantação
Ao publicar a aplicação, utilize o comando dotnet publish -c Release -r win-x64 para gerar os binários autocontidos. Ao registrar múltiplos serviços no mesmo servidor, mantenha um padrão de nomenclatura rigoroso para os nomes e descrições, facilitando a identificação e manutenção via Gerenciador de Serviços do Windows.