Usuário com melhor resposta
WindowsService para sem explicação

Pergunta
-
Senhores,
Boa noite. Eu fiz a minha primeira experiência com WindowsService, pois até então, eu só tinha usado asp.net e windows forms. A aplicação é simples, eu coloquei um Timer no namespace System.Threading e implementei um código simples. Funciona assim:
Quando chega um determinado horário, ele faz a leitura de uma tabela, verifica se tem registro em um terminado dia e envia um e-mail se não for encontrado nenhum registro. O objetivo desse serviço é monitorar cargas de arquivos texto para dentro uma tabela em um banco de dados. Se a consulta não retornar nenhum registro, signifca que carga de arquivo não aconteceu ou houve falha e me envia um e-mail para eu tomar as providências.
Ele chega executar essa rotina no horário, mas depois da primeira execução, o serviço simples "para". No segundo dia em diante, essa rotina não é mais executada porque o serviço está parado. Eu estou procurando alguma coisa no site da Microsoft, mas por enquanto eu não encontrei nada. Eu não fiz nenhuma configuração específica, eu praticamente usei as configurações do Template do Visual Studio 2010.
Alguém já passou por isso e sabe como resolver?
Desde já agradeço pela ajuda.
Carlos Henrique Meireles
Respostas
-
Cara,
Primeiro vamos esclarecer duas coisas:
Windows Services: Aplicação windows que fica sendo executada em background no S.O.
Objeto Timer: Objeto disponivel na plataforma .NET para executarmos funcionalidades em um determinado espaço de tempo.
Para que o timer funcione de acordo com o proposto temos que adicionar ao nosso objeto Timer, um EventHandler(ElapsedEventHandler) ele executará as funcionalidades codificadas respeitando o intervalo informado ao objeto. Ao invés de arrata-lo na mão, declarando ele da forma que eu fiz funciona perfeitamente seguindo as regras.
protected override void OnStart(string[] args) { timer.Elapsed += new ElapsedEventHandler(OnElapsedTime); //Metodo Aqui timer.Interval = Convert.ToInt32(ConfigurationManager.AppSettings["TEMPO"]); //Tempo Aqui timer.Enabled = true; }
private void OnElapsedTime(object source, ElapsedEventArgs e)
{
//....
}
Agora quanto ao seu questionamento de depuração de uma aplicação windows service.
Bom quando vou fazer isso, ou eu tenho uma aplicação comum para depurar e depois passar para windows service, ou eu escreve informações em um arquivo texto referente ao método(Em qual método ele está o que ele está fazendo, etc..) e vou atualizando esse arquivo para ter uma noção se tudo está ok.
Segue uma dica.
Atenciosamente,
Samuel dos Anjos
Atenciosamente, Samuel dos Anjos
- Marcado como Resposta Henrique Meireles quarta-feira, 21 de novembro de 2012 12:04
Todas as Respostas
-
-
Ok.
Segue o código da classe que herda ServiceBase:
public partial class SPrincipal : ServiceBase { private CPrincipal cPrincipal = new CPrincipal(); public SPrincipal() { InitializeComponent(); cPrincipal.InitializeComponent(elgNavDataLoader); } protected override void OnStart(string[] args) { cPrincipal.OnStart(args); } protected override void OnStop() { cPrincipal.OnStop(); } }
Segue o código da minha classe de controle (Controller)
class CPrincipal { private Timer _timer; private SLog _sLog; private String _NomeDoArquivoLog; private System.Diagnostics.EventLog _EventLog; private STarefasAgendadas sTarefasAgendadas; private Boolean _LogAtivado = false; public void InitializeComponent(System.Diagnostics.EventLog pEventLog) { _EventLog = pEventLog; if (!System.Diagnostics.EventLog.SourceExists("elgNavDataLoader")) { System.Diagnostics.EventLog.CreateEventSource( "elgNavDataLoader", "wsNavDataLoaderLog"); } _EventLog.Source = "elgNavDataLoader"; _EventLog.Log = "wsNavDataLoaderLog"; } public void OnStart(string[] args) { String vCaminhoDoArquivoLog = ConfigurationSettings.AppSettings["CaminhoArquivoLog"].ToString(); String vNomeDoArquivo = ConfigurationSettings.AppSettings["NomeArquivoLog"].ToString(); sTarefasAgendadas = new STarefasAgendadas(this); //******** Objetos que serao usado pelo Timmer *****************/ AutoResetEvent autoEvent = new AutoResetEvent(false); TimerCallback timercallback = sTarefasAgendadas.Execute_Elapsed; //**************************************************************/ _NomeDoArquivoLog = vCaminhoDoArquivoLog + vNomeDoArquivo; if (!Directory.Exists(vCaminhoDoArquivoLog)) { _EventLog.WriteEntry("Não foi possível inciar timer porque o caminho do arquivo de log não é válido."); } else { try { _sLog = new SLog(_NomeDoArquivoLog); _EventLog.WriteEntry("Serviço iniciado."); InserirLog("OnStart", "Timer iniciado."); _timer = new Timer(timercallback, autoEvent, 1000, 31000); _LogAtivado = true; } catch (Exception e) { _EventLog.WriteEntry("Erro ao iniciar o serviço. " + e.Message); InserirLog("OnStart", "Erro ao iniciar o serviço. " + e.Message); } } } public void OnStop() { if (_LogAtivado) InserirLog("OnStop", "Serviço paralisado. "); _EventLog.WriteEntry("Serviço paralisado."); _timer.Dispose(); } public void InserirLog(string pEvento, string pObservacao) { _sLog.Inserir(pEvento, pObservacao); } public void TarefaEmExecucao(bool pAtivar) { if (pAtivar) _sLog.Inserir("Tarefa agendada iniciada", ""); else _sLog.Inserir("Tarefa agendada concluída", ""); } }
Segue abaixo o código da classe de serviço onde estão implementadas as tarefas que deverão ser executadas em determinados horários:
class STarefasAgendadas { private INotificadorExecucao _NotificadorExecucao; /* Refatorar para criar esses objetos dinâmicamente*/ private CMonitoracaoProcessamento _cMonitoracaoProcessamento; private Task tarefaAgendada1; /**********************************************************************************/ public STarefasAgendadas(INotificadorExecucao pNotificadorExecucao) { _NotificadorExecucao = pNotificadorExecucao; /* Refatorar para criar esses objetos dinâmicamente*/ /**********************************************************************************/ _cMonitoracaoProcessamento = new CMonitoracaoProcessamento(_NotificadorExecucao); tarefaAgendada1 = new Task(() => _cMonitoracaoProcessamento.Executar()); /**********************************************************************************/ } public void Execute_Elapsed(Object stateInfo) { if (DateTime.Now.ToShortTimeString() == "08:15") { if (tarefaAgendada1.Status != TaskStatus.Running) tarefaAgendada1.Start(); } } }
Espero que possa me ajudar.Carlos Henrique Meireles
-
Cara,
Quando for chamar o timer tente fazer assim:
protected override void OnStart(string[] args)
{
timer.Elapsed += new ElapsedEventHandler(OnElapsedTime); //Metodo Aqui
timer.Interval = Convert.ToInt32(ConfigurationManager.AppSettings["TEMPO"]); //Tempo Aqui
timer.Enabled = true;
}private void OnElapsedTime(object source, ElapsedEventArgs e)
{
//....
}
Atenciosamente,
Samuel dos Anjos
Atenciosamente, Samuel dos Anjos
- Sugerido como Resposta Samuel Rodrigues dos Anjos quarta-feira, 14 de novembro de 2012 22:13
-
Caro Samuel,
Obrigado pela tentativa em me ajudar. O tmmer que você me sugere usar é do namespace do WindowsForms. O timer que estou usando é do namespace System.Threading. Esse timer que você me sugere não funciona em aplicações WindowService. Eu não sei te dizer porque não funciona, mas eu tentei usá-lo antes e realmente não dispara os eventos no tempo programado. Eu li isso aqui mesmo no fórum e outro tópico.
Eu estou depurando a aplicação para ver se encontro algum problema na rotina que eu implementei. Eu não consegui descobrir ainda porque não é possível depurar aplicações windowsservice. Eu estou escrevendo mais testes unitários para aumentar a cobertura e com isso espero identificar o erro. Se eu conseguir, eu postarei aqui.
Enquanto isso, se você tiver alguma outra dica, será muito bem vinda.
Um abraço,
Carlos Henrique Meireles
-
Cara,
Primeiro vamos esclarecer duas coisas:
Windows Services: Aplicação windows que fica sendo executada em background no S.O.
Objeto Timer: Objeto disponivel na plataforma .NET para executarmos funcionalidades em um determinado espaço de tempo.
Para que o timer funcione de acordo com o proposto temos que adicionar ao nosso objeto Timer, um EventHandler(ElapsedEventHandler) ele executará as funcionalidades codificadas respeitando o intervalo informado ao objeto. Ao invés de arrata-lo na mão, declarando ele da forma que eu fiz funciona perfeitamente seguindo as regras.
protected override void OnStart(string[] args) { timer.Elapsed += new ElapsedEventHandler(OnElapsedTime); //Metodo Aqui timer.Interval = Convert.ToInt32(ConfigurationManager.AppSettings["TEMPO"]); //Tempo Aqui timer.Enabled = true; }
private void OnElapsedTime(object source, ElapsedEventArgs e)
{
//....
}
Agora quanto ao seu questionamento de depuração de uma aplicação windows service.
Bom quando vou fazer isso, ou eu tenho uma aplicação comum para depurar e depois passar para windows service, ou eu escreve informações em um arquivo texto referente ao método(Em qual método ele está o que ele está fazendo, etc..) e vou atualizando esse arquivo para ter uma noção se tudo está ok.
Segue uma dica.
Atenciosamente,
Samuel dos Anjos
Atenciosamente, Samuel dos Anjos
- Marcado como Resposta Henrique Meireles quarta-feira, 21 de novembro de 2012 12:04
-
Caro Samuel,
Suas explicações ficaram claras mim. Obrigado.
Quanto ao problema depuração, eu fiz exatamente o que você me sugeriu, criei um arquivo de logo e mandei escrever nele cada método que o serviço fosse executado, mas nenhum erro ocorre durante a execução da rotina. Eu não se te explicar direito porque ainda estou analisando. Eu só sei te dizer que, que ocorre um erro que capturei no log de eventos do Windows logo depois que o método é executado.
Application: wsNavDataLoader.exe Framework Version: v4.0.30319 Description: The process was terminated due to an unhandled exception. Exception Info: System.InvalidOperationException Stack: at System.Threading.Tasks.Task.Start(System.Threading.Tasks.TaskScheduler) at System.Threading.Tasks.Task.Start() at wsNavDataLoader.Servico.STarefasAgendadas.Execute_Elapsed(System.Object) at System.Threading._TimerCallback.TimerCallback_Context(System.Object) at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean) at System.Threading._TimerCallback.PerformTimerCallback(System.Object)
Não consegui identificar porque essa mensagem está acontecendo. De qualquer forma, eu seguirei a sua orientação e logo em seguida postarei aqui.
Carlos Henrique Meireles
-
Henrique, boa tarde
Você já olhou o EventLog?, por padrão uma aplicação Windows service sempre grava informações lá de inicio, parada e erro
Bruno Viegas D. Ribeiro
Analista Desenvolvedor de Sistemas www.brunoviegas.com.br -
-
Eu não tinha percebido, me desculpe
Coloque um try no método
public void Execute_Elapsed(Object stateInfo){...}
para ver se ele mostra o erroBruno Viegas D. Ribeiro
Analista Desenvolvedor de Sistemas www.brunoviegas.com.br -
Caro Samuel,
Eu alterei o objeto Timer do namespace System.Threading para o Timer do namespace System.Timers conforme sua dica e deu certo. Instalei o serviço e deixei executando dois dias. Está certinho. Muito obrigado.
Bruno,
Obrigado pela sua ajuda também.
Muito bom esse fórum.
Carlos Henrique Meireles
-