web-dev-qa-db-ja.com

.NET-「すべての例外ハンドラをキャッチ」を実装する最良の方法は何ですか

「他のすべてが失敗した場合にキャッチ」するのが最善の方法だと思います。

つまり、あなたはアプリケーションでできるだけ多くの例外を処理していますが、それでもバグがあるはずなので、未処理の例外をすべてキャッチして、情報を収集してデータベースに保存したり送信したりする必要がありますWebサービスへ。

AppDomain.CurrentDomain.UnhandledExceptionイベントはすべてをキャプチャしますか?アプリケーションがマルチスレッドである場合でも?

サイドノート:Windows VistaはネイティブAPI関数を公開します。これにより、クラッシュ後にアプリケーションが自動的に回復できるようになりました...今はその名前を思い付くことができません... Windows XP。

75
TimothyP

AppDomainのUnhandledException動作を試しました(これは未処理の例外が登録される最後の段階です)

はい、イベントハンドラを処理した後、アプリケーションが終了し、厄介な「...プログラムが動作ダイアログを停止しました」が表示されます。

:)あなたはstillそれを避けることができます。

チェックアウト:

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)の未処理を上位レベルで処理します。

33

ASP.NETでは、Application_ErrorファイルでGlobal.asax関数を使用します。

WinFormsでは、ApplicationEventsファイルでMyApplication_UnhandledExceptionを使用します

これらの関数は両方とも、コードで未処理の例外が発生した場合に呼び出されます。例外をログに記録し、これらの関数からユーザーにNiceメッセージを提示できます。

16
ine

Winformアプリケーションの場合、AppDomain.CurrentDomain.UnhandledExceptionに加えて、 Application.ThreadException および Application.SetUnhandledExceptionMode (UnhandledExceptionMode.CatchException)を使用します。この組み合わせはすべてをキャッチするようです。

13
Bob Nadler

メインスレッドには、次のオプションがあります。

他のスレッドの場合:

  • セカンダリスレッドには未処理の例外はありません。 SafeThread を使用します
  • ワーカースレッド:(タイマー、スレッドプール)セーフティネットがまったくありません!

これらのイベントはhandle例外ではなく、単にreportであることに注意してくださいそれらをアプリケーションに提供します-多くの場合、それらについて有用な/正気なことをするには遅すぎます

例外のログ記録は適切ですが、アプリケーションの監視はより適切です;-)

警告:私は SafeThread 記事の著者です。

6
Steven A. Lowe

WinFormsの場合、現在のスレッドの未処理の例外イベントにもアタッチすることを忘れないでください(特にマルチスレッドを使用している場合)。

ベストプラクティスに関するいくつかのリンク here および here および here(おそらく.netの最良の例外処理記事)

4
Bogdan Maxim

[〜#〜] elmah [〜#〜] と呼ばれるクールなものもあります。これは、Webアプリケーションで発生したASP.NETエラーをログに記録します。 Winform Appソリューションについて質問していることは承知していますが、これはこの種のことをWebアプリで必要とする人にとって有益だと感じました。私は仕事の場でそれを使用し、デバッグに非常に役立ちました(特に本番サーバーで!)

ここにいくつかの機能があります(ページのすぐ外に引っ張られます):

  • ほとんどすべての未処理の例外のログ。
  • 記録された例外のログ全体をリモートで表示するWebページ。
  • ログに記録された例外の詳細をリモートで表示するWebページ。
  • 多くの場合、customErrorsモードがオフになっている場合でも、ASP.NETが特定の例外に対して生成した死の元の黄色い画面を確認できます。
  • 発生時の各エラーの電子メール通知。
  • ログからの最新の15エラーのRSSフィード。
  • インメモリ、Microsoft SQL Server、およびコミュニティから提供されたいくつかを含む、ログの多くのバッキングストレージ実装。
2
Ryan Abbott

マルチスレッドアプリでもそのハンドラーのほとんどの例外を監視できますが、.NET(2.0以降)では、1.1互換モードを有効にしない限り、未処理の例外をキャンセルできません。それが発生すると、AppDomainは何があってもシャットダウンされます。最善の方法は、この例外を処理し、新しいAppDomainを作成してアプリを再起動できるように、異なるAppDomainでアプリを起動することです。

2
jezell

私は次のアプローチを使用していますが、これは機能し、コードの量を大幅に削減します(しかし、より良い方法があるのか​​、それの落とし穴があるのか​​わかりません。あなたが電話するときはいつでも:彼らの行動を明確にするのに十分;)

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 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
0
Yordan Georgiev

マネージGUIアプリケーションでは、デフォルトで、GUIスレッドで発生した例外はApplication.ThreadExceptionに割り当てられたものによって処理されます。

他のスレッドで発生した例外は、AppDomain.CurrentDomain.UnhandledExceptionによって処理されます。

GUIスレッドの例外を非GUIの例外と同様に動作させ、AppDomain.CurrentDomain.UnhandledExceptionによって処理されるようにするには、次のようにします。

Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException);

ThreadExceptionを使用してGUIスレッド例外をキャッチすることの利点は、アプリを継続させるオプションを使用できることです。構成ファイルがデフォルトの動作をオーバーライドしていないことを確認するには、次を呼び出します。

Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);

あなたは依然として、正常に動作しないネイティブdllからの例外に対して脆弱です。ネイティブdllがWin32 SetUnhandledExceptionFilterを使用して独自のハンドラーをインストールする場合、以前のフィルターへのポインターを保存して呼び出すことも想定されています。そうしないと、ハンドラーは呼び出されません。

0
Corey Trager