Criando Windows Services com C# de forma fácil

Alberto Monteiro
albertomonteiro
Published in
5 min readApr 13, 2016

Windows Service

Windows Service é um aplicativo que roda em background. Simples assim.
Os serviços windows podem ser configurados para iniciar junto com o sistema operacional e ficar rodando junto com o SO, eles também podem ser iniciados de forma manual.

Para mais detalhes você pode conferir o que a Wikipedia fala sobre windows services.

Windows Service e o Visual Studio

O Visual Studio desde sempre disponibilizou um template de projeto para a criação de um Windows Service, inclusive já utilizei bastante ele, mas infelizmente trabalhar com ele era realmente trabalhoso, era complicado para instalar, para debugar, desinstalar, etc…Já tive muita dor de cabeça para lidar com essas particularidades, e como gosto de facilitar minha vida, sempre procurei alternativas que fossem melhores. Finalmente eu encontrei uma, e seu nome é TopShelf.

Se você estiver curioso para saber como é feito a criação de um windows service com o visual studio, da uma olhada nesse artigo no msdn.

Introduzindo o TopShelf

O TopShelf é um pacote nuget(e isso é lindo), além disso, ele é muito simples, tem uma boa documentação, e até agora nunca tive dor de cabeça com ele.

Criando um Windows Service com TopShelf

Para criar o Windows Service, você não vai usar o template de projeto que o Visual Studio provê para essa finalidade. Você deve usar um Console Application. Após criar sua console application, instale o pacote do topshelf via nuget

Install-Package Topshelf

Agora você já deve ter acesso a classe HostFactory que vai possibilitar a configuração e execução do Windows Service. Abaixo você pode ver o código da classe Program usando o TopShelf.

public class Program
{
public static void Main(string[] args)
{
HostFactory.Run(configurator =>
{
configurator.Service<GeradorDeRelatorio>(s =>
{
s.ConstructUsing(name => new GeradorDeRelatorio());
s.WhenStarted((service, control) => service.Start(control));
s.WhenStopped((service, control) => service.Stop(control));
});
configurator.RunAsLocalSystem();

configurator.SetDescription("Sample Topshelf Host");
configurator.SetDisplayName("Stuff");
configurator.SetServiceName("Stuff");
});
}
}

Avaliando o código podemos ver que é muito simples usar a API do TopShelf para criar e executar o Windows Service, simplesmente chamamos o método Run da classe HostFactory e passamos uma função como argumento que é responsável por realizar a configuração do serviço. Essa função recebe um parâmetro do tipo HostConfigurator e é por meio dele que vamos realizar todas as configurações.

  1. O método Service que é genérico serve para definir qual é a classe que representa o Windows Service. Além disso, esse método também recebe uma função para configurar algumas particularidades do serviço.
  2. O método RunAsLocalSystem, faz exatamente o que o nome dele diz, configura o Windows Service para rodar como Local System

Além disso, você vê que outros detalhes do Windows Service são configurados posteriormente, por meio dos métodos SetDescription, SetDisplayName e SetServiceName. A classe HostConfigurator dispõe de uma grande quantidade de métodos para configuração do seu serviço. Para você ter uma ideia de quão poderoso é o TopShelf, ele provê eventos para que sejam escutados processos antes/depois da instalação do Windows Service, entre outros eventos.

O próximo passo agora é escrever a classe que vai representar nosso Windows Service, segue ela abaixo.

public sealed class GeradorDeRelatorio : ServiceControl
{
private readonly CancellationTokenSource _cancellationTokenSource;

public GeradorDeRelatorio()
{
_cancellationTokenSource = new CancellationTokenSource();
}

public bool Start(HostControl hostControl)
{
Task.Run(() =>
{
while (true)
{
//Gera relatorio
Thread.Sleep(TimeSpan.FromSeconds(5));
}
}, _cancellationTokenSource.Token);
return true;
}

public bool Stop(HostControl hostControl)
{
_cancellationTokenSource.Cancel();
_cancellationTokenSource.Dispose();
return true;
}
}

A classe GeradorDeRelatorio é o Windows Service, fiz ela implementar uma interface que o TopShelf já disponibiliza, que é a ServiceControl, e essa interface exige que eu implemente dois métodos, o Start e o Stop.

No construtor da minha classe, simplesmente crio um CancelationTokenSource para poder cancelar minha tarefa quando o serviço for parado.

O método Start é bem simples, eu uso o Task.Run para criar uma execução FAF(Fire And Forget) que nada mais é que um processamento que vai ser realizado em outra Thread e não quero receber nenhum retorno dele. Sendo assim, dentro da função que vai ser executada em outra thread, faço um loop infinito e dentro do loop, executarei a geração do relatório, logo em seguida a thread para por 5 segundos, e então repete tudo novamente.

O método Stop, simplesmente chama o método Cancel e Dispose do canceletationTokenSource que vai fazer com que o processo FAF pare de executar.

O que fizemos nessa classe não é nada diferente do que poderíamos fazer com o convencional template de windows service que o VS tem.

Com 11 linhas de código, usamos o TopShelf para criar/executar nosso serviço, e isso já é o suficiente para termos o windows service funcional.

Resolvendo os problemas

Eu mencionei lá em cima que era muito chato de lidar com algumas coisas do windows service criado pelo template do visual studio, vou listar cada um e explicar como o TopShelf resolveu de maneira linda!!!

Debug

Antes para debugar um serviço Windows, eu tinha que instalar o serviço, usando o próprio visual studio, ou usando o executável installutil, iniciar o serviço através da interface de serviços do windows, e então no visual studio atachar o debugger no processo do serviço windows, ou fazer tudo isso que disse anteriormente e substituir o ultimo passo por outro que era escrever a linha de código System.Diagnostics.Debugger.Launch() na primeira linha de execução do meu serviço, isso fazia com que uma janela abrisse perguntando se eu queria debugar, ai eu selecionava a instância do VS e começava a debugar.

Mas agora que temos TopShelf, simplesmente aperto F5, e debugo normalmente de forma leve e tranquila, sem nenhuma dor de cabeça!!!!

Instalação

Para instalar o windows service, ou eu usava o exe que já mencionei aqui, o installutil que fica no diretório do .NET Framework, ou então criar um projeto de um instalador no visual studio, que gera um msi e faz a instalação do serviço por mim.

Mas agora que temos TopShelf, simplesmente executo o exe que ele gerou passando um parâmetro, que é o install ficando assim: MeuServicoWindows.exe install.

Desinstalação

Tão chato quanto os processos para fazer a instalação, a desinstalação também é chata, ou usava o installutil ou o instalador(msi) que foi criado pelo visual studio. Além disso, isso me deixava tão confuso, que eu deletava o exe, e o serviço ficava instalado, ai eu compilava novamente mas o installutil já não conseguia desinstalar, e isso me dava uma dor de cabeça tão grande que eu parava para relaxar e depois voltava para resolver o problema.

Mas agora que temos TopShelf, simplesmente executo o exe que ele gerou passando um parâmetro, que é o uninstall ficando assim: MeuServicoWindows.exe uninstall.

TopShelf é tudo de bom

Como bom desenvolvedor você deve seguir os princípios SOLID, e para facilitar a respeitar o último princípio eu gosto de usar algum container de IoC(inverção de controle/inversion of control) para criar minhas classes, e o TopShelf já suporta isso nativamente, ele tem implementação que aceita a maioria dos IoC containers de mercado.

Digamos que você queria usar o Ninject, basta instalar o pacote Topshelf.Ninject e na função que configura o serviço, você vai chamar alguns métodos a mais:

configurator.UseNinject(new MeuNinjectModule(), new MeuNinjectModule2());

E dentro da função de configuração passada para o método Service você vai adicionar a seguinte linha:

s.ConstructUsingNinject();

No final, a configuração completa deve ficar desse jeito:

O TopShelf é um projeto Open Source e está no GitHub, o link dele é esse aqui.

Outra coisa muito legal é que ele é cross-platform, ele funciona no Linux através do Mono tranquilamente.

Para finalizar deixo abaixo o link do site do TopShelf.

Vou ficando por aqui, não deixe de comentar, um grande abraço!

--

--