简体   繁体   English

.NET - 实现“捕获所有异常处理程序”的最佳方法是什么

[英].NET - What's the best way to implement a “catch all exceptions handler”

I'm wondering what the best way is to have a "if all else fails catch it". 我想知道最好的方法是“如果所有其他方法都失败了”。

I mean, you're handling as much exceptions as possible in your application, but still there are bound to be bugs, so I need to have something that catches all unhandled exceptions so I can collect information and store them in a database or submit them to a web service. 我的意思是,你在应用程序中处理尽可能多的异常,但仍然存在bug,所以我需要有一些东西可以捕获所有未处理的异常,这样我就可以收集信息并将它们存储在数据库中或提交它们到网络服务。

Does the AppDomain.CurrentDomain.UnhandledException event capture everything? AppDomain.CurrentDomain.UnhandledException事件是否捕获了所有内容? Even if the application is multithreaded? 即使应用程序是多线程的?

Side note: Windows Vista exposes native API functions that allow any application to recover itself after a crash... can't think of the name now... but I'd rather not use it, as many of our users are still using Windows XP. 旁注:Windows Vista公开了本机API函数,允许任何应用程序在崩溃后自行恢复...现在无法想到名称...但我宁愿不使用它,因为我们的许多用户仍在使用Windows XP。

I have just played with AppDomain's UnhandledException behavior, (this is the last stage the unhandled exception is registered at) 我刚刚玩过AppDomain的UnhandledException行为,(这是未处理的异常注册的最后一个阶段)

Yes, after processing the event handlers your application will be terminated and the nasty "... program stopped working dialog" shown. 是的,在处理事件处理程序后,您的应用程序将被终止,并显示令人讨厌的“...程序停止工作对话框”。

:) You still can avoid that. :)你仍然可以避免这种情况。

Check out: 查看:

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();
    }
}

PS Do handle the unhandled for Application.ThreadException (WinForms) or DispatcherUnhandledException (WPF) at the higher level. PS处理更高级别的Application.ThreadException(WinForms)或DispatcherUnhandledException(WPF)的未处理。

In ASP.NET, you use the Application_Error function in the Global.asax file. 在ASP.NET中,您使用Global.asax文件中的Application_Error函数。

In WinForms, you use the MyApplication_UnhandledException in the ApplicationEvents file 在WinForms中,您在ApplicationEvents文件中使用MyApplication_UnhandledException

Both of these functions are called if an unhandled exception occurs in your code. 如果代码中出现未处理的异常,则会调用这两个函数。 You can log the exception and present a nice message to the user from these functions. 您可以记录异常并从这些函数向用户显示一条好消息。

For Winform applications, in addition to AppDomain.CurrentDomain.UnhandledException I also use Application.ThreadException and Application.SetUnhandledExceptionMode (w/ UnhandledExceptionMode.CatchException). 对于Winform应用程序,除了AppDomain.CurrentDomain.UnhandledException之外,我还使用Application.ThreadExceptionApplication.SetUnhandledExceptionMode (w / UnhandledExceptionMode.CatchException)。 This combination seems to catch everything. 这种组合似乎抓住了一切。

On the main thread, you have the following options: 在主线程上,您有以下选项:

For other threads: 对于其他线程:

  • Secondary threads have no unhandled-exceptions; 辅助线程没有未处理的异常; use SafeThread 使用SafeThread
  • Worker threads: (timer, threadpool) there is no safety net at all! 工作者线程:(计时器,线程池)根本没有安全网!

Bear in mind that these events do not handle exceptions, they merely report them to the application--often when it is far too late to do anything useful/sane about them 请记住,这些事件不会处理异常,它们只会将它们报告给应用程序 - 通常是在对它们做任何有用/明智的事情为时已晚。

Logging exceptions is good, but monitoring applications is better ;-) 记录异常是好的,但监控应用程序更好;-)

Caveat: I am the author of the SafeThread article. 警告:我是SafeThread文章的作者。

For WinForms, don't forget to attach to the current Thread's unhandled exception event too (especially if you are using multi threading). 对于WinForms,不要忘记附加到当前Thread的未处理异常事件(特别是如果您使用多线程)。

Some links on best practices here and here and here (probably the best exception handling article for .net) 关于这里这里这里的最佳实践的一些链接(可能是.net的最佳异常处理文章)

There's also a cool thing called ELMAH that will log any ASP.NET errors that occur in a web application. 还有一个很酷的东西叫ELMAH ,它会记录Web应用程序中出现的任何ASP.NET错误。 I know you're asking about a Winform App solution, but I felt this could be beneficial to anyone needing this type of thing on a web app. 我知道你在询问Winform App解决方案,但我觉得这对于在网络应用上需要这种类型的任何人都有好处。 We use it where I work and it's been very helpful in debugging (especially on production servers!) 我们在工作的地方使用它,它在调试时非常有用(特别是在生产服务器上!)

Here's some features that it has (pulled right off the page): 这里有一些功能(从页面上拉出):

  • Logging of nearly all unhandled exceptions. 记录几乎所有未处理的异常。
  • A web page to remotely view the entire log of recoded exceptions. 用于远程查看重新编码的异常的整个日志的网页。
  • A web page to remotely view the full details of any one logged exception. 用于远程查看任何一个已记录异常的完整详细信息的网页。
  • In many cases, you can review the original yellow screen of death that ASP.NET generated for a given exception, even with customErrors mode turned off. 在许多情况下,您可以查看ASP.NET为给定异常生成的原始黄色死亡屏幕,即使关闭了customErrors模式也是如此。
  • An e-mail notification of each error at the time it occurs. 每个错误发生时的电子邮件通知。
  • An RSS feed of the last 15 errors from the log. 来自日志的最后15个错误的RSS提要。
  • A number of backing storage implementations for the log, including in-memory, Microsoft SQL Server and several contributed by the community. 日志的许多后备存储实现,包括内存,Microsoft SQL Server和社区贡献的几个。

You can monitor most exceptions in that handler even in multithreaded apps, but .NET (starting with 2.0) won't allow you to cancel unhandled exceptions unless you enable the 1.1 compatibility mode. 即使在多线程应用程序中,您也可以监视该处理程序中的大多数异常,但.NET(从2.0开始)将不允许您取消未处理的异常,除非您启用1.1兼容模式。 When that happens the AppDomain will be shut down no matter what. 当发生这种情况时,AppDomain将被关闭,无论如何。 The best you could do is launch the app in a different AppDomain so that you can handle this exception and create a new AppDomain to restart the app. 您可以做的最好的事情是在不同的AppDomain中启动应用程序,以便您可以处理此异常并创建一个新的AppDomain来重新启动应用程序。

In a manged GUI app, by default, exceptions that originate in the GUI thread are handled by whatever is assigned to the Application.ThreadException. 在magedd GUI应用程序中,默认情况下,源自GUI线程的异常由分配给Application.ThreadException的任何内容处理。

Exceptions that originate in the other threads are handled by AppDomain.CurrentDomain.UnhandledException. 源自其他线程的异常由AppDomain.CurrentDomain.UnhandledException处理。

If you want your GUI thread exceptions to work just like your-non GUI ones, so that they get handled by AppDomain.CurrentDomain.UnhandledException, you can do this: 如果您希望GUI线程异常与非GUI GUI一样工作,以便它们由AppDomain.CurrentDomain.UnhandledException处理,您可以这样做:

Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException);

An advantage to catching the GUI thread exceptions using ThreadException is that you can give the use the options of letting the app continue. 使用ThreadException捕获GUI线程异常的一个优点是,您可以使用让应用程序继续运行的选项。 To make sure no config files are overriding default behavior, you can call: 要确保没有配置文件覆盖默认行为,您可以调用:

Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);

You are still vulnerable to exceptions from badly behaved native dlls. 您仍然容易受到行为不端的本机dll的异常攻击。 If a native dll installs its own handler using Win32 SetUnhandledExceptionFilter, it is supposed to save the pointer to the previous filter and call it too. 如果本机dll使用Win32 SetUnhandledExceptionFilter安装自己的处理程序,则应该将指针保存到前一个过滤器并调用它。 If it doesn't do that, your handler wont' get called. 如果不这样做,你的处理程序就不会被调用。

I am using the following approach, which works and reduces greatly the amount of code ( yet I am not sure if there is a better way or what the pitfalls of it might be. Whenever you call: I quess the quys giving minuses would be polite enough to clarify their actions ; ) 我正在使用以下方法,它可以工作并大大减少代码量(但我不确定是否有更好的方法或它的缺陷可能是什么。无论何时你打电话:我认为给予弊端的qu is会礼貌足以澄清他们的行为;)

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

And here is the ErrorHandler code : Just to make clear- : objUser - is the object modelling the appusers ( you might get info such as domain name , department , region etc. for logging purposes ILog logger - is the logging object - eg the one performing the logging activities StackTrace st - the StackTrace object giving you debugging info for your app 这里是ErrorHandler代码:只是为了清楚 - :objUser - 是为appusers建模的对象(你可能会获得诸如域名,部门,区域等信息用于记录目的ILog logger - 是日志记录对象 - 例如一个执行日志记录活动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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 在dotnet / .NET中实现自定义属性的最佳方法是什么? - What's the best way to implement custom attributes in dotnet/.NET? 捕获所有异常或特定异常的断路器的最佳实践是什么? - What is the best practice for a Circuit Breaker, catch all Exceptions or specific ones? 在C#.NET中捕获所有未处理异常的简便方法 - Easy way to catch all unhandled exceptions in C#.NET 什么是处理异常以及如何在asp.net中处理它们的最佳方法 - What's the best way to handle the exceptions and how to deal with them in asp.net 捕获异常的推荐方法是什么 - What is the recommended way to catch exceptions 实施搜索的最佳方法是什么? - What's the best way to implement a search? 在代码的整个生命周期中处理异常的最佳方法是什么? - What's the best way to handle exceptions over the lifetime of your code? 在 C# 中处理异步 HttpWebRequest 异常的最佳方法是什么? - What's the best way to handle asynchronous HttpWebRequest exceptions in C#? 为ASP.NET MVC Intranet应用程序实施Windows身份验证的最佳方法是什么? - What's the best way to implement Windows Authentication for an ASP.NET MVC intranet application? 在多租户.net项目中实现角色的最佳方法是什么? - What's the best way to implement roles in a multi-tenant .net project?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM