Pergunta

É possível usar um manipulador UnhandledException em um serviço do Windows?

Normalmente eu usaria um componente de tratamento de exceções personalizado que faz registro, telefona para casa, etc.Este componente adiciona um manipulador a System.AppDomain.CurrentDomain.UnhandledException mas, pelo que posso dizer, isso não resulta em nada em um serviço do Windows, então acabo com esse padrão em meus 2 (ou 4) pontos de entrada de serviço:


    Protected Overrides Sub OnStart(ByVal args() As String)
        ' Add code here to start your service. This method should set things
        ' in motion so your service can do its work.
        Try
            MyServiceComponent.Start()
        Catch ex As Exception
            'call into our exception handler
            MyExceptionHandlingComponent.ManuallyHandleException (ex)
            'zero is the default ExitCode for a successfull exit, so if we set it to non-zero
            ExitCode = -1
            'So, we use Environment.Exit, it seems to be the most appropriate thing to use
            'we pass an exit code here as well, just in case.
            System.Environment.Exit(-1)
        End Try
    End Sub

Existe uma maneira de meu componente Tratamento de exceções personalizado lidar melhor com isso, para que eu não precise preencher meu OnStart com um encanamento confuso de tratamento de exceções?

Foi útil?

Solução

Ok, fiz um pouco mais de pesquisa sobre isso agora.Ao criar um serviço Windows em .Net, você cria uma classe que herda de System.ServiceProcess.ServiceBase (em VB, isso está oculto no arquivo .Designer.vb).Em seguida, você substitui as funções OnStart e OnStop e OnPause e OnContinue, se desejar.Esses métodos são invocados de dentro da classe base, então dei uma olhada no refletor.OnStart é invocado por um método em System.ServiceProcess.ServiceBase chamado ServiceQueuedMainCallback.A versão na minha máquina "System.ServiceProcess, Version=2.0.0.0" é descompilada assim:


Private Sub ServiceQueuedMainCallback(ByVal state As Object)
    Dim args As String() = DirectCast(state, String())
    Try 
        Me.OnStart(args)
        Me.WriteEventLogEntry(Res.GetString("StartSuccessful"))
        Me.status.checkPoint = 0
        Me.status.waitHint = 0
        Me.status.currentState = 4
    Catch exception As Exception
        Me.WriteEventLogEntry(Res.GetString("StartFailed", New Object() { exception.ToString }), EventLogEntryType.Error)
        Me.status.currentState = 1
    Catch obj1 As Object
        Me.WriteEventLogEntry(Res.GetString("StartFailed", New Object() { String.Empty }), EventLogEntryType.Error)
        Me.status.currentState = 1
    End Try
    Me.startCompletedSignal.Set
End Sub

Então, como Me.OnStart(args) é chamado de dentro da parte Try de um bloco Try Catch, presumo que tudo o que acontece dentro do método OnStart é efetivamente encapsulado por esse bloco Try Catch e, portanto, quaisquer exceções que ocorram não são tecnicamente tratadas como na verdade, eles são tratados no Try Catch ServiceQueuedMainCallback.Portanto, CurrentDomain.UnhandledException nunca acontece, pelo menos durante a rotina de inicialização.Os outros 3 pontos de entrada (OnStop, OnPause e OnContinue) são todos chamados da classe base de maneira semelhante.

Então eu ‘acho’ que isso explica por que meu componente Exception Handling não consegue capturar UnhandledException no início e na parada, mas não tenho certeza se isso explica por que os temporizadores configurados no OnStart não podem causar uma UnhandledException quando disparam.

Outras dicas

Você pode assinar o Evento AppDomain.UnhandledException.Se você tiver um loop de mensagem, poderá vincular ao Evento Application.ThreadException.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top