代码之家  ›  专栏  ›  技术社区  ›  Tobi

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

  •  3
  • Tobi  · 技术社区  · 16 年前

    我刚刚在一个.NET2.0应用程序中修复异常处理,我偶然发现了一些奇怪的问题 Application.ThreadException .

    我想要的是能够捕获GUI元素背后事件(例如,按钮单击等)的所有异常。然后,我想根据“致命性”筛选这些异常,例如,对于某些类型的异常,应用程序应继续运行,而对于其他类型的异常,应用程序应退出。

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

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

    那么,如何从这个事件中获得整个异常链呢? 我是否有可能或者需要以另一种方式设计例外处理?

    workaround Application.SetUnhandledExceptionMode ,但这远远不是理想的,因为我必须滚动自己的消息循环。

    编辑:为了防止更多的错误, GetBaseException()方法不符合我的要求 :它只返回最内部的异常,而我仅有的是最内部的异常。我想得到最外面的例外!

    7 回复  |  直到 7 年前
        1
  •  3
  •   Community kfsone    7 年前
        2
  •  1
  •   Vincent Van Den Berghe    16 年前


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

       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
    


    这是我在HandleappeException中得到的结果(即ThreadExceptionEventArgs):

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

    如果您只是捕获并(重新)抛出异常,则不会显示InnerExceptions,但它将附加到异常中。 ,例如:

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

        3
  •  1
  •   Tamas Czinege    16 年前

    通常,只有在Application.ThreadException异常处理程序中发生异常时,才会丢失整个异常链(Application.ThreadException异常处理程序中的基本异常除外)。

    MSDN Library :

    此事件允许您使用Windows窗体 申请以其他方式处理 中发生的未处理异常 线程。附上你的 ThreadException的事件处理程序 事件来处理这些例外情况, 这将使你的申请留在 未知状态。在可能的情况下,

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

        4
  •  1
  •   iszzypop    15 年前

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

        5
  •  0
  •   Leo Moore    16 年前

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

    exception.getbaseexception Method

        6
  •  0
  •   Queue    9 年前

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

        7
  •  -1
  •   Leo Moore    16 年前

    根据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
    

    我觉得这正是你要找的。