4

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

我想要的是能够从 GUI 元素后面的事件中捕获所有异常(例如 button_Click 等)。然后我想在“致命”上过滤这些异常,例如,对于某些类型的异常,应用程序应该继续运行,而对于其他类型的异常,它应该退出。

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

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

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

请注意,我确实有一个使用Application.SetUnhandledExceptionMode的解决方法,但这远非理想,因为我必须推出自己的消息循环。

编辑:为了防止更多错误,GetBaseException() 方法不会做我想要的:它只返回最里面的异常,而我唯一已经拥有的是最里面的异常。我想了解最外面的异常!

4

7 回答 7

3

这个问题在这里更有用地表达和回答:

为什么内部异常到达 ThreadException 处理程序而不是实际抛出的异常?

于 2009-08-04T17:25:26.963 回答
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):

线程异常 http://mediasensation.be/dump/?download=ThreadException.jpg

如果您只是捕获并(重新)抛出异常,则不会出现 InnerExceptions,但它会附加到异常中。StackTrace,像这样:

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

于 2008-11-21T10:41:35.843 回答
1

通常,如果异常发生在其他线程中,您只会丢失除 Application.ThreadException 异常处理程序中的基本异常之外的整个异常链。

MSDN 库

此事件允许您的 Windows 窗体应用程序处理在Windows 窗体线程中发生的其他未处理的异常 。将您的事件处理程序附加到 ThreadException 事件以处理这些异常,这将使您的应用程序处于未知状态。在可能的情况下,异常应该由结构化的异常处理块来处理。

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

于 2008-11-21T10:58:24.420 回答
1

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

于 2009-12-09T02:06:45.873 回答
0

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

exception.getbaseexception 方法

于 2008-09-14T14:18:04.360 回答
0

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

于 2015-03-06T01:25:23.153 回答
-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

这会让我觉得正是你正在寻找的东西。

于 2008-09-14T21:03:27.210 回答