3 de fev. de 2009

Debugando windows services


"Cannot start service from the command line or a debugger."

Fazia tempo que não via essa mensagem.
Precisei debugar um windows service num projeto esses dias e lembrei que uma coisa interessante: o nosso amigo F5 não funciona !
Simplesmente não adianta botar uns breakpoints e apertar F5 como acontece com os projetos Windows, Web, etc.
O Windows Service funciona como um serviço, portanto é necessário compila-lo, depois instala-lo,etc.
Se você tentar executar um serviço com o F5, a seguinte mensagem aparecerá:


debug-servicos-2005

"Incomodada ficava sua avó!"

Nas buscas pela web a solução para debugar windows services é quase sempre colocar seu breakpoint no visual studio, rodar seu serviço (via windows) e "attachar" seu debugger ao processo.

Nem sempre funciona.

Quase todo serviço windows funciona a base de thread que rodam periodicamente.
Um serviço, quando iniciado, roda automaticamente o metodo OnStart(), onde normalmente se criam outras threads de monitoramento e/ou eventos periódicos.
Dai que enquanto você está tentando attachar o seu processo, o evento já pode ter passado !
Outras soluções incluem criar um aplicativo Windows de teste para executar os métodos principais do seu windows services, ou então invocar o Debugger programaticamente via System.Diagnostics.Debugger.Break()  ou System.Diagnostics.Debugger.Launch().
Ai lembrei que já tinha feito algo parecido no framework 1 ainda com o falecido Visual Studio 2003.

A estrutura básica de um windows service contem os métodos OnStart(), OnStop(),etc

Sendo que a chamada principal se parece com isso.


Program.cs

static void Main()
{
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[] { new MeuServicoWindows() };
ServiceBase.Run(ServicesToRun);
}


E a classe do serviço:  MeuServicoWindows.cs


public class MeuServicoWindows : ServiceBase
{
public MeuServicoWindows()
{
}
protected override void OnStart(string[] args)
{
// faça-se o trampo !!
}
protected override void OnStop()
{
// Simon diz, pare-se.
}
}



A solução ideal é criar um meio termo.
Como a chamada principal do Windows Service é sempre a Main() e depois a OnStart() da classe do Servico, a solução para o simples F5 seria


1) Criar um metodo na classe do serviço        
#if DEBUG
public void StartDebug(string[] args)
{
OnStart(args); // simplesmente chama a rotina principal da classe
}
#endif


2) Substituir o  o metodo principal Main()
       
static void Main()
{
// se estiver debugando, simula a execução do serviço...
if (System.Diagnostics.Debugger.IsAttached)
{
#if DEBUG // debugando como DEBUG
MeuServicoWindows service = new MeuServicoWindows();
service.StartDebug(new string[2]);
System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite);
#else // debugando como Release
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[] { new MeuServicoWindows() };
ServiceBase.Run(ServicesToRun);
#endif
}
else // codigo original
{
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[] { new MeuServicoWindows() };
ServiceBase.Run(ServicesToRun);
}
}


Pontos de interesse da solução:
1) É possível debugar em ambiente de desenvolvimento;
2) É possível colocar uma versão de debug em produção
3) É possível colocar uma versão de release em produção

Postar um comentário