none
WindowsService para sem explicação RRS feed

  • 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

    segunda-feira, 12 de novembro de 2012 23:07

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

    domingo, 18 de novembro de 2012 01:11

Todas as Respostas

  • Cara,

    Posta o seu código ai, que talvez eu possa tentar lhe ajudar.


    Atenciosamente,
    Samuel dos Anjos

    Atenciosamente, Samuel dos Anjos

    segunda-feira, 12 de novembro de 2012 23:30
  • 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

    terça-feira, 13 de novembro de 2012 00:17
  • 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

    terça-feira, 13 de novembro de 2012 23:55
  • 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

    sexta-feira, 16 de novembro de 2012 11:54
  • 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

    domingo, 18 de novembro de 2012 01:11
  • 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

    segunda-feira, 19 de novembro de 2012 15:44
  • 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
     

    segunda-feira, 19 de novembro de 2012 16:08
  • Olá Bruno,

    Sim, foi exatamente o que fiz. Eu extraí essa mensagem de lá. Estou depurando para ver encontro o problema. Estou partindo para ideia do Samuel e vou se vai resolver. 


    Carlos Henrique Meireles

    segunda-feira, 19 de novembro de 2012 16:19
  • 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 erro

    Bruno Viegas D. Ribeiro

    Analista Desenvolvedor de Sistemas
    www.brunoviegas.com.br
     

    segunda-feira, 19 de novembro de 2012 16:30
  • 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

    quarta-feira, 21 de novembro de 2012 12:06
  • Blz cara,

    Qualquer dúvida poste ai, pois estamos todos aqui para aprender uns com os outros.

    Atenciosamente,

    Samuel dos Anjos


    Atenciosamente, Samuel dos Anjos

    quarta-feira, 21 de novembro de 2012 18:28