如何在Application.ThreadException事件处理程序中获取整个Exceptions链?

时间:2008-09-14 14:08:16

标签: .net winforms exception

我正在努力修复.NET 2.0应用程序中的异常处理,我偶然发现了Application.ThreadException的一些奇怪问题。

我想要的是能够捕获GUI元素背后事件的所有异常(例如button_Click等)。然后,我想在'死亡'上过滤这些例外情况,例如:对于某些类型的异常,应用程序应该继续运行,而其他应该退出。

在另一个.NET 2.0应用程序中,我了解到,默认情况下,仅在调试模式下,异常实际上会留下Application.Run或Application.DoEvents调用。在发布模式下,这不会发生,并且必须使用Application.ThreadException事件“捕获”异常。

但是,现在,我注意到在Application.ThreadException事件的ThreadExceptionEventArgs中传递的异常对象始终是异常链中最内层的异常。为了记录/调试/设计目的,我真的想要整个异常链。例如,当您处理SocketException时,确定外部系统失败并不容易:当它被包装为例如一个NpgsqlException,至少你知道这是一个数据库问题。

那么,如何从这个事件中获得整个异常链?甚至可能还是我需要以另一种方式设计我的异常处理?

请注意,我使用workaround进行了Application.SetUnhandledExceptionMode,但这远非理想,因为我必须滚动自己的消息循环。

编辑:为了防止出现更多错误, GetBaseException()方法不能做我想做的事情:它只返回最内层的异常,而我唯一拥有的是最内层的异常。我想得到最外层的例外!

7 个答案:

答案 0 :(得分:3)

答案 1 :(得分:1)

我试图重现这种行为(总是得到最内层的例外),
但我得到了我期望的异常,所有的InnerExceptions都完好无损。

以下是我用来测试的代码:

   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处理Application.ThreadException。首先调用Test1()方法 这是我在HandleAppException中得到的结果(e As ThreadExceptionEventArgs):

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

如果您只是捕获并且(重新)抛出异常,则不会显示InnerExceptions,但它会被附加到异常。 StackTrace ,如下所示:

  

在Test.vb中的SO.Test3():第166行   在Test.vb的SO.Test2()中:第159行   在Test.vb中的SO.Test1():第151行

答案 2 :(得分:1)

通常情况下,除了Application.ThreadException异常处理程序中的基本异常(如果异常发生在另一个线程中)之外,您只会丢失整个异常链。

来自MSDN Library

  

此事件允许您的Windows窗体   申请处理否则   未处理的异常发生在    Windows窗体主题。附上你的   ThreadException的事件处理程序   处理这些例外的事件,   这将留下你的申请   一个未知的状态。在可能的情况,   例外应由a处理   结构化异常处理块。

解决方案:如果您进行了线程处理,请确保所有线程/异步调用都在try / catch块中。或者如您所说,您可以使用Application.SetUnhandledExceptionMode。

答案 3 :(得分:1)

刚发现一些有趣的东西。不同的GUI事件将为您带来不同的结果。从Form.Shown事件处理程序抛出的异常将导致Application.ThreadException捕获最内部异常,但在Form.Load事件中运行完全相同的代码将导致最外层异常陷入Application.ThreadException。

答案 4 :(得分:0)

您是否尝试过Exception.GetBaseException方法?这将返回创建Application.TreadException的异常。然后,您可以使用相同的流程上链以获取所有异常。

exception.getbaseexception Method

答案 5 :(得分:0)

根据此链中的一些信息,我使用UnhandledExceptionMode.ThrowException而不是UnhandledExceptionMode.CatchException。然后我在表单的Run()之外捕获异常,这给了我整个异常链。

答案 6 :(得分:-1)

根据MSDN文档:

在派生类中重写时,返回异常,该异常是一个或多个后续异常的根本原因。

    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

您可以使用此变体来解析异常链。

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

这会让我感觉到你正在寻找的东西。