65.9K
CodeProject 正在变化。 阅读更多。
Home

一个简单的类来捕获 WinForms 中未处理的异常

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.64/5 (28投票s)

2006年7月24日

4分钟阅读

viewsIcon

204036

downloadIcon

3798

解释如何捕获未处理的异常,并将堆栈跟踪以及其他调试信息发送给开发人员。

Demo Screenshot

引言

大家都知道异常处理的重要性:没人希望看到无意义的错误消息、应用程序崩溃,甚至(过去经常发生)“蓝屏死机”。幸运的是,C# 和其他许多现代语言一样,提供了强大的 try-catch-finally 函数集,看似可以帮助我们预防常见的错误。但并非所有情况都适用。

想象一下,你的应用程序使用了大量的第三方组件或类,而你没有它们的源代码,甚至连好的文档都没有(这听起来很熟悉,不是吗?)。在这种情况下,你的应用程序的可靠性取决于你使用的每个类的可靠性。因此,你可能甚至不知道何时会遇到异常,以及在哪里捕获它。你不太可能捕获所有异常,尤其是当你不知道如何应对它们时。

另一方面,在测试期间从用户那里获得错误报告可能会非常有益。微软已经在其操作系统中包含了这样的功能(请参见下面的截图),但所有这些报告都将发送给微软,而不是发送给遇到问题的应用程序的开发人员。

Microsoft Unhandled exception notification

注意:实际上,有一种方法可以获取已提交给微软供你的客户使用的错误信息:你可以订阅 Microsoft Windows 错误报告服务(请参见下面的链接)。但对于小型公司和独立开发人员来说,这个选项并不便宜:你需要从 VeriSign 购买数字证书(起价 499 美元)。

幸运的是,.NET 提供了像 UnhandledException 事件这样强大的功能,我们可以提供类似的功能来获得通知。

Using the Code

让我们仔细看看本文随附演示项目中的 UnhandledExceptionDlg 类。

UnhandledExDlg Class diagram

首先,我们需要为一个处理 Application.ThreadException 事件的事件处理程序分配一个处理器,为后者分配 AppDomain.CurrentDomain.UnhandledException 事件的处理器,并设置 Application.SetUnhandledExceptionModeUnhandledExceptionMode.CatchException,以强制所有 Windows Forms 错误通过我们的处理器,而不管应用程序用户配置文件中的设置。UnhandledExDlg 在其默认构造函数中执行此操作。

Application.ThreadException += new 
  ThreadExceptionEventHandler(ThreadExceptionFunction);
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
AppDomain.CurrentDomain.UnhandledException += new 
  UnhandledExceptionEventHandler(UnhandledExceptionFunction);

函数 UnhandledExceptionFunction 接受与 AppDomain.CurrentDomain.UnhandledException 相同的参数,即 objectUnhandledExceptionEventArgs,并返回 void

基本上,这个函数只是放入一些参数,如事件日期/时间、应用程序名称等,设置“重启应用程序”复选框(见下文详情),然后打开对话框窗口。

该类有一个公共属性 bool RestartApp = true。此属性对应于对话框上的“重启应用程序”复选框,而你,作为开发人员,应该检查其值,并在需要时执行一些恢复工作。

为了获取用户反馈,你应该处理两个类事件:OnShowErrorReportOnSendExceptionClick。第一个事件与“点击这里”链接标签相关联。该链接向用户显示将要发送的信息类型。如果你不处理此事件,则链接及其描述将隐藏。OnSendExceptionClick 在用户单击“发送报告”按钮时触发。你必须处理它,以提供发送异常信息的传输方式。它可以是 HTTP POST、SMTP、FTP 等。如果你不处理此事件,“发送报告”按钮将处于禁用状态。以下是如何使用这些事件的示例:

// Here is your react to user request to show him what information will be sent
exDlg.OnShowErrorReport += delegate(object sender, 
                           SendExceptionClickEventArgs ar)
{
    System.Windows.Forms.MessageBox.Show("Handle OnShowErrorReport" + 
           " event to show what you are going to send.\n" +
           "For example:\n" + ar.UnhandledException.Message + 
           "\n" + ar.UnhandledException.StackTrace + 
           "\n" + (ar.RestartApp ? "This App will be restarted." : 
           "This App will be terminated!"));
};

// Yes! User wants to send!
exDlg.OnSendExceptionClick += delegate(object sender, 
                              SendExceptionClickEventArgs ar)
{
    // User clicked on "Send Error Report" button:
    if(ar.SendExceptionDetails)
        // --- Implement your send transport here ---

    // User wants to restart the App:
    if(ar.RestartApp)
    {
        // --- Perform data restoration if needed and restart your App
        // System.Diagnostics.Process.Start(
        //        System.Windows.Forms.Application.ExecutablePath);
    }
};

SendExceptionClickEventArgs 扩展了 System.EventArgs,并有三个附加参数

// TRUE if user clicked on "Send Error Report"
// button and FALSE if on "Don't Send"
bool SendExceptionDetails;
// Used to store captured exception
Exception UnhandledException;
// Contains user's request: should the App to be restarted or not
bool RestartApp;

即时调试

这涉及到如何抑制 Visual Studio JIT 对话框窗口,该窗口会在每次捕获到未处理的异常时打开。如果你想抑制此对话框,可以在 IDE 的“选项”菜单的“调试”部分取消选中“启用异常助手”。

Microsoft Visual Studio 2005

VS 2005 Options Dialog

Microsoft Visual Studio 2003

VS 2003 Options Dialog

如果你还想禁用计算机上的 Windows “发送错误报告”对话框,请右键单击“我的电脑”图标,选择“属性”,切换到“高级”选项卡,然后单击“错误报告”按钮。在“选项”对话框中,选择“禁用错误报告”单选按钮。

Disable Error reporting

这就是 UnhandledExceptionDlg 的全部内容。请不要犹豫提交你的意见和建议。

关注点

历史

  • 2006 年 9 月 26 日 - 添加了对 ThreadExceptionSetUnhandledExceptionMode 的处理(感谢所有引起我注意的人!)。演示项目也已更新。
  • 2006 年 8 月 29 日 - 更新了有关 Microsoft Windows 错误报告服务及其链接的信息。
  • 2006 年 7 月 24 日 - 初始版本发布。
© . All rights reserved.