我想知道最好的方法是什么“如果一切都失败了”。

我的意思是,您在应用程序中处理尽可能多的例外,但是仍然有错误,因此我需要有一些捕获所有未手持异常的东西,以便我可以收集信息并将其存储在数据库中或提交它们到Web服务。

AppDomain.CurrentDomain.UnhandledException 事件是否捕获所有内容?即使应用程序是多线程的?

边注:Windows Vista 公开允许任何应用程序的本机 API 函数 在崩溃后恢复自己......现在想不出名字了...但我宁愿不要 使用它,因为我们的许多用户仍在使用 Windows XP。

有帮助吗?

解决方案

我刚刚玩过AppDomain的UnhandledException行为, (这是未处理的异常在注册的最后阶段)

是的,在处理事件处理程序之后,您的应用程序将被终止并且令人讨厌的“...程序停止工作对话框”所示。

:) 你仍然可以避免这种情况。

退房:

class Program
{
    void Run()
    {
        AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);

        Console.WriteLine("Press enter to exit.");

        do
        {
            (new Thread(delegate()
            {
                throw new ArgumentException("ha-ha");
            })).Start();

        } while (Console.ReadLine().Trim().ToLowerInvariant() == "x");


        Console.WriteLine("last good-bye");
    }

    int r = 0;

    void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
    {
        Interlocked.Increment(ref r);
        Console.WriteLine("handled. {0}", r);
        Console.WriteLine("Terminating " + e.IsTerminating.ToString());

        Thread.CurrentThread.IsBackground = true;
        Thread.CurrentThread.Name = "Dead thread";            

        while (true)
            Thread.Sleep(TimeSpan.FromHours(1));
        //Process.GetCurrentProcess().Kill();
    }

    static void Main(string[] args)
    {
        Console.WriteLine("...");
        (new Program()).Run();
    }
}

P.S。在较高级别处理Application.ThreadException(WinForms)或DispatcherUnhandledException(WPF)的未处理。

其他提示

在ASP.NET中,您使用 Global.asax 文件中的 Application_Error 函数。

在WinForms中,您使用 ApplicationEvents 文件中的 MyApplication_UnhandledException

如果代码中出现未处理的异常,则会调用这两个函数。您可以记录异常并从这些函数向用户显示一条好消息。

对于Winform应用程序,除了AppDomain.CurrentDomain.UnhandledException之外,我还使用 Application.ThreadException Application.SetUnhandledExceptionMode (带有UnhandledExceptionMode.CatchException)。这种组合似乎抓住了一切。

在主线程上,您有以下选项:

对于其他线程:

  • 辅助线程没有未处理的异常;使用 安全线程
  • 工作线程:(计时器、线程池)根本没有安全网!

请记住,这些事件并不 处理 例外,他们只是 报告 将它们传递给应用程序——通常当对它们做任何有用/理智的事情时已经太晚了

记录异常很好,但监视应用程序更好;-)

警告:我是该书的作者 安全线程 文章。

对于WinForms,不要忘记附加到当前Thread的未处理异常事件(特别是如果您使用多线程)。

有关最佳做法的一些链接此处这里这里(可能是.net的最佳异常处理文章)

还有一个很酷的东西叫 埃尔玛 它将记录 Web 应用程序中发生的任何 ASP.NET 错误。我知道您正在询问 Winform 应用程序解决方案,但我认为这对任何在网络应用程序上需要此类内容的人来说都是有益的。我们在工作的地方使用它,它对调试非常有帮助(特别是在生产服务器上!)

以下是它具有的一些功能(直接从页面上拉出):

  • 记录几乎所有未处理的异常。
  • 用于远程查看记录的异常的整个日志的网页。
  • 用于远程查看任何记录的异常的完整详细信息的网页。
  • 在许多情况下,您可以查看原始的黄屏死机 ASP.NET 为给定的对象生成的 异常,即使使用 customErrors 模式 关闭。
  • 每个错误发生时的电子邮件通知。
  • 日志中最后 15 个错误的 RSS 提要。
  • 日志的多种后备存储实现,包括 内存中、Microsoft SQL Server 和 一些由社区贡献。

即使在多线程应用程序中,您也可以监视该处理程序中的大多数异常,但.NET(从2.0开始)将不允许您取消未处理的异常,除非您启用1.1兼容模式。当发生这种情况时,AppDomain将被关闭,无论如何。您可以做的最好的事情是在不同的AppDomain中启动应用程序,以便您可以处理此异常并创建一个新的AppDomain来重新启动应用程序。

我正在使用以下方法,它可以工作并大大减少代码量(但我不确定是否有更好的方法或它的缺陷可能是什么。 每当你打电话: 我认为给予弊端的态度会礼貌地澄清他们的行为; )

try 
{
    CallTheCodeThatMightThrowException()
 }
catch (Exception ex)
{
    System.Diagnostics.StackTrace st = new System.Diagnostics.StackTrace ();
    Utils.ErrorHandler.Trap ( ref objUser, st, ex );
} //eof catch

这是ErrorHandler代码: 只是为了弄清楚 - :objUser - 是为appusers建模的对象(你可能会得到诸如域名,部门,区域等信息用于记录目的 ILog记录器 - 是记录对象 - 例如执行日志记录活动的人 StackTrace st - StackTrace对象为您提供应用程序的调试信息

using System;
using log4net; //or another logging platform

namespace GenApp.Utils
{
  public class ErrorHandler
  {
    public static void Trap ( Bo.User objUser, ILog logger, System.Diagnostics.StackTrace st, Exception ex )
    {
      if (ex is NullReferenceException)
      { 
      //do stuff for this ex type
      } //eof if

      if (ex is System.InvalidOperationException) 
      {
        //do stuff for this ex type
      } //eof if

      if (ex is System.IndexOutOfRangeException) 
      {
        //do stuff for this ex type
      } //eof if

      if (ex is System.Data.SqlClient.SqlException)
      {
        //do stuff for this ex type
      } //eof if

      if (ex is System.FormatException)
      {
        //do stuff for this ex type
      } //eof if

      if (ex is Exception)
      {
        //do stuff for this ex type
      } //eof catch

    } //eof method 

  }//eof class 
} //eof namesp

在magedd GUI应用程序中,默认情况下,源自GUI线程的异常由分配给Application.ThreadException的任何内容处理。

源自其他线程的异常由AppDomain.CurrentDomain.UnhandledException处理。

如果您希望GUI线程异常与非GUI GUI一样工作,以便它们由AppDomain.CurrentDomain.UnhandledException处理,您可以这样做:

Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException);

使用ThreadException捕获GUI线程异常的一个好处是,您可以使用让应用程序继续运行的选项。要确保没有配置文件覆盖默认行为,您可以调用:

Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);

您仍然容易受到行为不端的原生dll的异常攻击。如果本机dll使用Win32 SetUnhandledExceptionFilter安装自己的处理程序,则应该将指针保存到前一个过滤器并调用它。如果不这样做,你的处理程序就不会被调用。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top