如何在.NET应用程序中捕获所有异常/崩溃

40

可能是重复的问题:
.NET - 实现“捕获所有异常处理程序”的最佳方法是什么?

我有一个.NET控制台应用程序,它崩溃并显示一条消息给用户。 我的所有代码都在一个try{<code>} catch(Exception e){<stuff>}块中,但仍然会偶尔显示错误。

在Win32应用程序中,您可以通过安装各种异常处理程序来捕获所有可能的异常/崩溃:

/* C++ exc handlers */
_set_se_translator
SetUnhandledExceptionFilter
_set_purecall_handler
set_terminate
set_unexpected
_set_invalid_parameter_handler

在.NET世界中,相应的是什么,以便我可以处理/记录/消除所有可能的错误情况?


请记住,有许多途径可以使进程“崩溃”,每种方式可能需要特殊的技巧来捕获 - 所有这些方式都是在托管异常导致应用程序崩溃的基础上的。最后一个复杂性是,例如 WinForms 可能会通过在到达应用程序全局异常处理程序之前捕获异常来干扰您的尝试。 - Roman Starkov
11个回答

44

您可以向AppDomain.UnhandledException事件添加一个事件处理程序,当发生未被捕获的异常时,该处理程序将被调用。


2
设置AppDomain.UnhandledException似乎与调用Win32 SetUnhandledExceptionFilter的工作方式完全相同。如果您的应用程序的另一部分安装了过滤器,则AppDomain.UnhandledException将正确地“链接”并调用其他过滤器。 - Corey Trager

29

与其他人发布的相反,捕获所有异常并没有什么问题。重要的是适当地处理它们。如果出现堆栈溢出或内存不足的情况,应用程序应该关闭它们。此外,请记住,OOM条件可能会阻止您的异常处理程序正确运行。例如,如果您的异常处理程序显示带有异常消息的对话框,如果您的内存不足,可能没有足够的内存来显示对话框。最好记录并立即关闭。

正如其他人提到的那样,您可以处理UnhandledException和ThreadException事件以收集可能被忽略的异常。然后只需在主循环周围抛出异常处理程序(假设是WinForms应用程序)。

此外,您应该知道OutOfMemoryExceptions并不总是由于内存不足而引发的。OOM条件可能会触发各种异常,在您的代码中或框架中,这些异常不一定与真正的潜在条件有关。我经常看到InvalidOperationException或ArgumentException,而其根本原因实际上是内存不足。


2
我很惊讶这里没有更多的赞。Juanma通过捕获事件做出了很好的补充,但是这并不能涵盖所有情况。应该从中得出的信息是有时打破标准是可以接受的。使用明确功能捕获特定的异常类型,并有一个包装器来捕获和处理其他任何异常。如果你正在编写一个DLL,在我的经验中,你应该让一个类继承自exception,创建你的功能,将未处理的异常包装在InnerException属性中并抛出。 - Anthony Mason

11

10

Global.asax类是你的最后一道防线。请查看:

protected void Application_Error(Object sender, EventArgs e)

方法


5
注意:本答案适用于 ASP.NET 应用程序而非控制台应用程序。 - jason saldo

6

请注意,有些异常是危险的或者几乎无法捕获的。

  • OutOfMemoryException:在catch处理程序中进行的任何操作都可能分配内存(在CLR的托管或非托管部分),从而触发另一个OOM。
  • StackOverflowException:取决于CLR是否足够早地检测到它,您可能会收到通知。最糟糕的情况下,它只会终止进程。

4
尽管没有计划地捕获所有异常是一种不好的做法,但我认为应用程序应该以某种优雅的方式失败。崩溃不应该吓到用户,至少它应该显示错误描述、报告给技术支持人员的一些信息,并最好提供一个关闭应用程序并重新启动的按钮。在理想的情况下,应用程序应该能够将用户数据转储到磁盘上,然后尝试恢复它(但我认为这要求过高)。
无论如何,我通常使用:
AppDomain.CurrentDomain.UnhandledException

4
你可以使用AppDomain.CurrentDomain.UnhandledException来获取一个事件。

3

您也可以选择使用Application.ThreadException事件。

曾经我在开发一个运行在基于COM的应用程序内部的.NET应用程序时,这个事件非常有用,因为AppDomain.CurrentDomain.UnhandledException在这种情况下无法工作。


1
我认为你最好不要捕获所有的异常,而是让它们显示给用户。这样做的原因是你只应该捕获你能够实际处理的异常。如果你遇到某些会导致程序停止但仍然捕获它的异常,这可能会导致更严重的问题。
另外请阅读FAQ:为什么FxCop警告不要使用catch(Exception)?

3
是的,但在应用程序完全崩溃之前能够记录所有信息(堆栈跟踪、所有依赖项的版本,可能还有屏幕截图)会很不错... - Benjol

1
请注意,捕获这些未处理的异常可能会改变您的应用程序的安全要求。在某些情况下(例如从网络共享运行时等),您的应用程序可能无法正确运行。请务必进行彻底的测试。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接