我正在努力修复.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()方法不能做我想做的事情:它只返回最内层的异常,而我唯一拥有的是最内层的异常。我想得到最外层的例外!答案 0 :(得分:3)
这个问题在这里更有用的措辞和答案:
Why does the inner exception reach the ThreadException handler and not the actual thrown exception?
答案 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的异常。然后,您可以使用相同的流程上链以获取所有异常。
答案 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
这会让我感觉到你正在寻找的东西。