Desvendando os mistérios dos Windows Services – Parte 2

 

Olá pessoal,

 

Dando continuidade ao artigo irá ser tratada agora a parte que mais interessa a todos: a construção.

 

Só relembrando que este artigo está separado em duas partes.

1ª Parte – Descrição de todas as suas principais características.

2ª Parte – Construir do zero um Windows Service, ou seja, mão na massa.

 

Não deixem de ler ou mesmo reler a primeira parte do artigo que é fundamental para o entendimento da construção.

 

A idéia do sistema que será criado é de um cenário comum hoje em dia: atualizar um arquivo Xml ao longo do dia. Este simples exemplo poderia ter o propósito de atualizar o site da própria empresa, enviar esse arquivo xml para seus clientes, para seus vendedores, para jornais etc.

 

Este artigo irá simular uma agência de notícias de esportes que tem como objetivo disponibilizar um arquivo Xml com as notícias produzidas ao longo do dia em um diretório onde os jornais tivessem acesso a cada 1 minuto. Essas notícias seriam inseridas pelos jornalistas em um BD que servirá então como fonte do arquivo Xml.

 

Obs.: Como o objetivo do artigo é demonstrar a criação e o funcionamento de um Windows Service não vamos entrar nos detalhes sobre ADO.NET e nem de possíveis funcionalidades que poderiam complementar o cenário descrito, como por exemplo enviar automaticamente o Xml das notícias via FTP, SMTP etc.

 

Descrito o cenário, vamos finalmente colocar a mão na massa.

 

Criando o Windows Service

Dentro do Visual Studio crie um novo projeto. Para isso clique em => File => New => Project.

 

Dentro da linguagem preferida escolha o tipo de projeto Windows Service como mostra a Figura 1 e preencha com o nome WSNoticias.

 

wsnoticiaspart2fig01.JPG
Figura 1 – Criando projeto Windows Service WSNoticias.

 

Depois de criado o projeto renomeie o serviço de Service1.vb para ServicoNoticias.vb.

 

Ainda no modo design acesse as propriedades do serviço (F4) e altere a propriedade Name e ServiceName para ServicoNoticias como mostra a Figura 2.

 

wsnoticiaspart2fig02.JPG

Figura 2 – Alterando as propriedades Name e ServiceName.

 

Agora clique na ToolBox na divisão Components e arraste o componente Timer para dentro do design do serviço.

 

Antes de ir para a programação do serviço deve-se preparar a estrutura básica do Banco de Dados para este serviço. Para isto execute o script abaixo dentro do BD Pubs já existente no seu SQL Server. Lembrando que para facilitar o artigo não serão levados em consideração itens básicos como chaves, índices, tipos de dados etc. que são imprescindíveis em um projeto real.

 

CREATE TABLE [Noticias] (

      [CodNoticia] [int] NOT NULL ,

      [Autor] [varchar] (200),

      [Noticia] [varchar] (1000) NOT NULL,

      [Data] [datetime]

) ON [PRIMARY]

GO

 

INSERT INTO Noticias VALUES ('1','Alex','São Paulo passa rasteira no Corinthians e contrata o centroavante Borges.',GetDate())

INSERT INTO Noticias VALUES ('2','Rafael','Corinthians contrata o fenômeno Cristian ex-Juventude.',GetDate())

INSERT INTO Noticias VALUES ('3','Marione','A brasileira Marta é eleita a melhor jogadora de futebol do mundo.',GetDate())

INSERT INTO Noticias VALUES ('4','Thiago','Carlos Alberto pode ter simulado contusão durante o campeonato brasileiro.',GetDate())

INSERT INTO Noticias VALUES ('5','Fabio ','Japão perde pela primeira vez o título por equipes do mundial de Kendo.',GetDate())

INSERT INTO Noticias VALUES ('6','Eduardo','O italiano Jarno Trulli pede para a sua equipe Toyota que o carro não quebre.',GetDate())

GO

 

Agora dê um duplo clique no design e vá ao Code onde já existe uma estrutura montada com a classe herdando o ServiceBase e os métodos OnStart e OnStop.

Copie o código abaixo dentro da classe ServicoNoticias substituindo os dois métodos OnStart e OnStop. Fique atento ao método Shared Sub Main localizado dentro da região escondida Generated Code na linha ServicesToRun = New System.ServiceProcess.ServiceBase() {New ServicoNoticias} onde entre essas últimas chaves deve ter o nome ServicoNoticias e não Service1.

 

Protected Overrides Sub OnStart(ByVal args() As String)

      'Habilitando o timer.

      Timer1.Enabled = True

      'O intervalo de tempo do objeto timer é setado em milesegundos. Portanto para 1 min. serão 60.000.

      Timer1.Interval = 60000

      'Gravando Log no Event Viewer para registrar que o serviço foi iniciado.

      EventLog.WriteEntry("O serviço Noticias foi iniciado com sucesso.", System.Diagnostics.EventLogEntryType.Information)

   End Sub

 

   Protected Overrides Sub OnStop()

      'Gravando Log no Event Viewer para registrar que o serviço parou.

      EventLog.WriteEntry("O serviço Noticias parou.", System.Diagnostics.EventLogEntryType.Warning)

   End Sub

 

   Private Sub Timer1_Elapsed1(ByVal sender As Object, ByVal e As System.Timers.ElapsedEventArgs) Handles Timer1.Elapsed

      'Gravando Log de teste para registrar cada passagem do timer. Em sistemas em produção essa log não deve existir.

      EventLog.WriteEntry("Timer 2 min.", System.Diagnostics.EventLogEntryType.Information)

      Try

         'Configurando comandos para busca na base de dados.

         Dim DataSetNoticias As New DataSet

         Dim Conexao As New System.Data.SqlClient.SqlConnection("integrated security=SSPI;data source=ALEXMORAES;initial catalog=pubs;")

         Dim Adapter As New System.Data.SqlClient.SqlDataAdapter

         Adapter.SelectCommand = New System.Data.SqlClient.SqlCommand("SELECT CodNoticia, Autor, Noticia, Data FROM Noticias", Conexao)

         Adapter.Fill(DataSetNoticias)

         'Gravando o arquivo Xml na raiz do drive C:

         DataSetNoticias.WriteXml("C:\NoticiasEsportes.xml")

      Catch ex As Exception

         'Gravando log no Event Viewer em caso de erro.

         EventLog.WriteEntry(ex.Message, System.Diagnostics.EventLogEntryType.Error)

      End Try

   End Sub

 

Instalando o Windows Service

Depois de criado o serviço é necessário criar um instalador para ele.

 

Volte ao design (F7) e clique com o botão direito do mouse no item Add Installer. Automaticamente será criado um novo arquivo chamado ProjectInstaller.vb que irá abrir já com 2 objetos existentes: ServiceProcessInstaller1 e ServiceInstaller1.

 

Estes dois objetos possuem importantes propriedades que deverão ser configuradas. Lembre que na primeira parte do artigo foram abordadas diversas delas e suas utilizações.

 

Clique em cima do ServiceProcessInstaller1 e pressione F4 para configurar a propriedade Account para LocalSystem.

 

Clique no ServiceInstaller1 e F4, alterando a propriedade StartType para Automatic como mostra a Figura 3.

 

wsnoticiaspart2fig03.JPG

Figura 3 – Alterando a propriedade StartType do objeto ServiceInstaller1.

 

Agora compile o projeto (menu Build => Build Solution). Por enquanto deixe no modo debug, mas lembre-se que sempre que for para produção deve-se compilar no modo Release.

 

O projeto está pronto. Agora será utilizado o instalador propriamente dito do .NET Framework: InstallUtil.exe. Para isso abra o command prompt do Visual Studio (se a máquina não possuir o VS instalado é possível utilizar o command prompt do Windows no diretório C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322).

 

Particularmente utilizo uma técnica para facilitar e não errar na digitação nesta parte, que consiste em ir até o diretório do projeto no Windows Explorer, abrir a pasta bin e copiar o caminho inteiro. Depois no command prompt do VS digito cd e clico com direito do mouse e colo o caminho completo. Pronto agora está bem mais fácil. Digite InstallUtil.exe WSNoticias.exe e execute (Figura 4).

 

wsnoticiaspart2fig04.JPG

Figura 4 – Diretório do projeto e comando de instalação InstallUtil.exe

 

Aguarde o processo de instalação que é transacional, portanto se algum problema ocorrer tudo é desfeito não deixando sujeira no sistema operacional. Verifique se as frases finais são The commit phase completed successfully e The transacted install has completed. Em caso afirmativo o serviço já está instalado com sucesso, como mostra a Figura 5.

 

wsnoticiaspart2fig05.JPG

Figura 5 – Instalação concluída com sucesso.

 

Para desinstalar o serviço basta utilizar o mesmo executável InstallUtil.exe com o parâmetro /u antes do nome do serviço. Exemplo: InstallUtil.exe /u WSNoticias.exe.

 

Iniciando e verificando o Windows Service

Agora vá até gerenciador de serviços que fica dentro das ferramentas administrativas da máquina. Abra o gerenciador e procure pela linha ServicoNoticias.

 

Após encontrar a linha de nosso serviço clique com o botão direito do mouse e clique em iniciar para startar o serviço como mostra a Figura 6.

 

wsnoticiaspart2fig06.JPG

Figura 6 – Gerenciador de Serviços. ServicoNoticias Iniciado.

 

Com isso o serviço já está rodando e trabalhando. Para verificar a sua funcionalidade abra o Visualizador de Eventos (Event Viewer) e dentro do item Aplicativo procure no campo fonte por ServicoNoticias e veja todos os eventos gravados como, por exemplo, serviço iniciado (Figura 7) e timer 1 min.

 

wsnoticiaspart2fig07.JPG

Figura 7 – Visualizador de Eventos. Propriedades do ServicoNoticias.

 

Por fim verifique na raiz do diretório C: o Xml gerado: NoticiasEsportes.xml.

 

Debugando o Windows Service

Uma das dificuldades da grande maioria das pessoas que trabalham com Windows Service é a parte de debug. Surgiram algumas lendas, algumas dizendo não ser possível debugar e outras afirmando ser super complicado. Abaixo será demonstrado que é bem simples e eficaz o debug de um Windows Service.

 

Após o serviço estar iniciado e conseqüentemente em execução abra o código fonte do serviço no VS e coloque algum ou alguns breakpoints dentro do método Timer1_Elapsed1.

 

Agora vá ao menu Tools => Debug Processes. Irá abrir uma nova janela de Processos. Nesta janela selecione a opção Show system processes que vem desabilitada por padrão e procure pelo serviço, que neste caso é o WSNoticias.exe (Figura 8).

 

wsnoticiaspart2fig08.JPG

Figura 8 – Processos em execução. Serviço WSNoticias.exe selecionado.

 

Depois de selecionado o serviço clique em Attach e selecione na nova janela apenas a primeira opção Common Language Runtime. Depois clique em Ok e o serviço será “atachado” ao VS pronto para o Debug (Figura 9).

 

wsnoticiaspart2fig09.JPG

Figura 9 – Attach do serviço.

 

Agora basta esperar o tempo configurado no timer para cair sobre o breakpoint já colocado(Figura 10).

 

wsnoticiaspart2fig10.JPG

Figura 10 – Debug parando no Breakpoint colocado.

 

Pessoal não deixe de estudar outros componentes interessantíssimos para se trabalhar com Windows Services. São eles:

  • FileSystemWatcher – Componente que monitora (ouve) um determinado diretório especificado verificando criação, exclusão e alteração de arquivos disparando algum evento quando qualquer destas ações ocorram.
  • DirectorySearcher – Componente que manipula serviços de diretórios como por exemplo o AD (Active Directory).

 

Com isso se encerra este artigo sobre Windows Service. Espero que seja útil para muitas pessoas e que finalmente tenha desvendado este falso mistério.

 

Abraços e até o próximo...