【问题标题】:How to disable .NET Framework exception handling and use my own instead?如何禁用 .NET Framework 异常处理并改用我自己的?
【发布时间】:2011-04-13 13:36:45
【问题描述】:

我已经开发了一个 .NET 4 软件,我准备将它发送给 beta 用户。如果软件中抛出未处理的异常,我想捕获它,记录它并将日志发送给我。我已经实现了这个功能,当我使用 Visual Studio 在调试模式下运行它时,它似乎运行良好。但是,当我构建并安装了该软件的发布版本时,Microsoft .NET Framework 开始在我的代码之前捕获异常。我收到一条带有错误消息的弹出窗口:“您的应用程序的组件中发生未处理的异常。如果您单击继续,应用程序将忽略此错误并尝试继续。”

为了测试崩溃,我创建了一个引发异常的崩溃按钮。此崩溃记录自身,异常处理程序记录所有收到的未处理异常。当我查看发布版本的日志时,我只能看到崩溃的日志消息,而不能看到异常处理程序的日志消息。

我已经用这段代码附加了我自己的异常处理程序:

AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;

有什么方法可以禁用 .NET Framework 的异常捕获,还是有更好的方法来附加我自己的异常处理程序?

更新:我正在使用 WPF。我将研究 DispatcherUnhandledException 并让您知道它是否解决了问题。

更新 #2: 不幸的是,将处理程序添加到 Application.Current.DispatcherUnhandledException 并没有解决问题。显然,此调试弹出窗口是由 Visual Studio 中包含的 JIT(即时)调试器创建的。我将不得不使用“平民”Windows 测试该软件,看看那里是否也捕获了异常。

更新 #3: 出于某种原因,使用 Visual Studio 构建的版本可以工作,但使用 MSBuild 脚本和 Dotfuscator 构建的版本不能。

【问题讨论】:

  • 在 WPF/Silverlight 中,设置 e.Handled = true 以防止异常继续向上堆栈。
  • 我还没能解决这个问题。当我这样做时,我会在这里发布答案。

标签: c# .net windows exception


【解决方案1】:

您尚未指定您正在使用哪个框架,但周围还有其他“未处理的异常”事件。

对于 Windows 窗体,有 Application.ThreadException

对于 WPF/Silverlight,有 Application.DispatcherUnhandledException

先尝试这两个中的一个,如果仍有问题,请告诉我们。

【讨论】:

    【解决方案2】:

    我终于解决了这个问题。该问题不是由于监听错误异常引起的,而是由于缺少发布版本中的 DLL。

    添加 DispatchedUnhandledException 和 ThreadException 事件的侦听器后,我不再看到奇怪的 Microsoft .NET Framework 弹出窗口,它允许用户在出现异常后继续运行软件。然而,我自己的异常处理在这一点上仍然被打破。

    因为在应该启动异常处理程序的那一刻软件已经崩溃,所以我在异常处理程序周围有一个捕获(异常)。删除此捕获后,我终于得到了正确的发布版本的错误消息并添加了缺少的 DLL。

    我(再次)学到的教训是:不要使用空的 catch (Exception) 块。这是邪恶的。

    【讨论】:

      【解决方案3】:

      听起来异常正在冒泡到您的应用程序的消息循环中。在 Windows 窗体中,您可以通过为 Application.ThreadException 事件设置事件处理程序来处理这些问题。在 WPF/Silverlight 中,等效事件为 Application.DispatcherUnhandledException

      您也可以在 Main 方法(如果有的话)中放置一个 try/catch 以进行良好的衡量,但 UI 通常会首先捕获异常,正如您所注意到的那样。

      编辑

      在 WPF/Silverlight 中,设置 e.Handled = true 以防止异常继续向上堆栈。

      【讨论】:

        【解决方案4】:

        哎哟... Dotfuscator 可能会为您生成一个不支持 JIT 的无效程序集。用户代码永远无法捕获 JIT 异常。这类似于您无法捕获StackOverflowException 的方式,因为运行时无法保证您可以安全地从遇到的错误条件中恢复。

        尽管如此,您在运行时遇到 JIT 异常的可能性很小,因为在您的 IL 和 JITer 之间存在不同的验证阶段。也许您有InvalidProgramExceptionBadImageFormatException?如果 JITter 真的失败了,这很可能是运行时中的错误,不应该发生。

        无论如何,你可以检查两件事:

        1. 在损坏/工作的程序集上运行 PEVerify 并比较输出。
        2. 在损坏的程序集上尝试 NGEN,看看是否会引发错误。

        【讨论】:

          【解决方案5】:

          您可以查看AppDomain class and the UnhandledException 事件和Application.ThreadException event。这些将捕获未处理的异常,至于您使用 try-catch 块自己处理的异常,您可以编写一个辅助类来管理您的异常并使用它们做您需要的事情。您甚至可以在该类中编写第三个事件来处理异常。

          【讨论】:

          • 他们说 AppDomain.UnhandledException 适用于您只能记录的异常。意味着你无法修复?但你仍然可以做 e.Handled = true
          【解决方案6】:
          // Add the event handler for handling UI thread exceptions to Windows Form Events.
              // Uses SystemThreading.
              // NOTE: Remember to turn Execption Handler OFF in the Debugger for testing!!  Debug -> Common Language Runtime Exceptions -> User-Unhandled -> OFF. 
              // NOTE: A separate Event Handler is Needed for other threads added to the Application.
              // NOTE: Methods can catch, inform, then throw for logging and emailing as well.
              // Add these to Program.cs.
              static void Main()
              {
                      Application.ThreadException += new ThreadExceptionEventHandler(Application_ThreadException);
          
                      // Set the unhandled exception mode to force all Windows Forms errors to go through the Handler.
                      Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
          
                     // ...
              }
          
              // Then put your handler in the method referenced in the event definition above.
              static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
              {
                   // Your Code ...
              }
          
            // Sorry for the ragged listing.  Still getting used to the editor here.
          

          【讨论】:

            【解决方案7】:

            try ... catch 阻止 Main() 有帮助吗?

            【讨论】:

            • 这不会处理其他线程中未处理的异常。
            【解决方案8】:

            来自 UnhandledException 事件的文档,

            此事件提供通知 未捕获的异常。它允许 应用程序记录有关信息 系统前的异常 默认处理程序报告异常 给用户并终止 应用。

            这只是一个钩子方法,您可以在其中插入自定义代码代码,在默认错误报告机制启动之前。未处理的异常将始终取消您的进程。它不允许您替换整个行为。

            我首先要质疑你的追求背后的需求..
            最简单的方法是采用一个团队约定,即 Main 和所有线程函数都有一个封闭的 try-catch。
            似乎有新的类型+事件(DispatcherUnhandledException)来捕获未处理的异常,但我会质疑它是否值得它拖入的复杂性。它应该是最后一道防线,而不是主要防线。
            例如如果在不同的线程中发生未处理的异常,则需要更多代码(因为异常不会跨线程路由,它只会终止进程)。

            【讨论】:

              猜你喜欢
              • 2013-03-08
              • 1970-01-01
              • 1970-01-01
              • 2017-01-01
              • 1970-01-01
              • 2016-03-16
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多