Como obter toda a cadeia de exceções no manipulador de eventos Application.ThreadException?

StackOverflow https://stackoverflow.com/questions/61354

  •  09-06-2019
  •  | 
  •  

Pergunta

Eu estava trabalhando na correção do tratamento de exceções em um aplicativo .NET 2.0 e me deparei com um problema estranho com Aplicação.ThreadException.

O que eu quero é poder capturar todas as exceções de eventos por trás de elementos GUI (por exemplo,botão_Clique, etc.).Quero então filtrar essas exceções por 'fatalidade', por ex.com alguns tipos de exceções o aplicativo deve continuar em execução e com outros deve sair.

Em outro aplicativo .NET 2.0, aprendi que, por padrão, apenas no modo de depuração as exceções realmente deixam uma chamada Application.Run ou Application.DoEvents.No modo release isso não acontece, e as exceções devem ser 'capturadas' utilizando o evento Application.ThreadException.

Agora, porém, notei que o objeto de exceção passado no ThreadExceptionEventArgs do evento Application.ThreadException é sempre a exceção mais interna na cadeia de exceções.Para fins de registro/depuração/design, eu realmente quero toda a cadeia de exceções.Não é fácil determinar qual sistema externo falhou, por exemplo, quando você apenas consegue lidar com uma SocketException:quando está embrulhado como, por exemplo.uma NpgsqlException, então pelo menos você sabe que é um problema de banco de dados.

Então, como chegar a toda a cadeia de exceções deste evento? É possível ou preciso projetar meu tratamento de exceções de outra maneira?

Observe que eu - mais ou menos - tenho um Gambiarra usando Application.SetUnhandledExceptionMode, mas isso está longe de ser o ideal porque eu teria que lançar meu próprio loop de mensagens.

EDITAR:para evitar mais erros, o método GetBaseException() NÃO faz o que eu quero:apenas retorna a exceção mais interna, enquanto a única coisa que já tenho é a exceção mais interna.Eu quero chegar à exceção mais externa!

Foi útil?

Solução

Esta pergunta é formulada e respondida de forma mais útil aqui:

Por que a exceção interna atinge o manipulador ThreadException e não a exceção real lançada?

Outras dicas

Tentei reproduzir esse comportamento (sempre obtendo a exceção mais interna),
mas recebo a exceção que espero, com todas as InnerExceptions intactas.

Aqui está o código que usei para testar:

   Private Shared Sub Test1()
      Try
         Test2()
      Catch ex As Exception
         Application.OnThreadException(New ApplicationException("test1", ex))
      End Try
   End Sub

   Private Shared Sub Test2()
      Try
         Test3()
      Catch ex As Exception
         Throw New ApplicationException("test2", ex)
      End Try
   End Sub

   Private Shared Sub Test3()
      Throw New ApplicationException("blabla")
   End Sub

Private Shared Sub HandleAppException(ByVal sender As Object, ByVal e As ThreadExceptionEventArgs)
...
End Sub

Sub HandleAppException lida com Application.ThreadException.O método Test1() é chamado primeiro.
Este é o resultado (e As ThreadExceptionEventArgs) que recebo em HandleAppException:

ThreadException http://mediasensation.be/dump/?download=ThreadException.jpg

Se você apenas capturar e (re)lançar exceções, nenhuma InnerExceptions aparecerá, mas será anexada à Exceção.StackTrace, assim:

em SO.Test3() em Test.vb:linha 166
em SO.Test2() em Test.vb:linha 159
em SO.Test1() em Test.vb:linha 151

Normalmente, você só perde toda a cadeia de exceções, exceto a exceção base em um manipulador de exceções Application.ThreadException, se a exceção ocorrer em outro thread.

De Biblioteca MSDN:

Este evento permite que o aplicativo Windows Forms lida com exceções não tratadas que ocorrem em Formulários do Windows tópicos.Anexe seus manipuladores de eventos ao evento ThreadException para lidar com essas exceções, o que deixará seu aplicativo em um estado desconhecido.Sempre que possível, as exceções devem ser tratadas por um bloco de manuseio de exceção estruturado.

Solução:Se você fizer threading, certifique-se de que todos os seus threads/chamadas assíncronas estejam em um bloco try/catch.Ou como você disse, você pode brincar com Application.SetUnhandledExceptionMode.

Acabei de descobrir algo interessante.Diferentes eventos da GUI proporcionarão resultados diferentes.Uma exceção lançada de um manipulador de eventos Form.Shown resultará em Application.ThreadException capturando a exceção mais interna, mas exatamente o mesmo código executado no evento Form.Load resultará no mais externo exceção sendo capturada em Application.ThreadException.

Você já tentou o método Exception.GetBaseException?Isso retorna a exceção que criou o Application.TreadException.Você poderia então usar o mesmo processo para subir na cadeia e obter todas as exceções.

exceção.getbaseexception Método

Com base em algumas informações desta cadeia, usei UnhandledExceptionMode.ThrowException em oposição a UnhandledExceptionMode.CatchException.Em seguida, capturo a exceção fora do Run() do formulário e isso me dá toda a cadeia de exceções.

De acordo com a documentação do MSDN:

Quando substituído em uma classe derivada, retorna a Exceção que é a causa raiz de uma ou mais exceções subsequentes.

    Public Overridable Function GetBaseException() As Exception
        Dim innerException As Exception = Me.InnerException
        Dim exception2 As Exception = Me
        Do While (Not innerException Is Nothing)
            exception2 = innerException
            innerException = innerException.InnerException
        Loop
        Return exception2
    End Function

Você poderia usar uma variação disso para analisar a cadeia de exceções.

Public Sub LogExceptionChain(ByVal CurrentException As Exception)

    Dim innerException As Exception = CurrentException.InnerException
    Dim exception2 As Exception = CurrentException

    Debug.Print(exception2.Message) 'Log the Exception

    Do While (Not innerException Is Nothing)

        exception2 = innerException
        Debug.Print(exception2.Message) 'Log the Exception

        'Move to the next exception
        innerException = innerException.InnerException
    Loop

End Sub

Isso me pareceria exatamente o que você está procurando.

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