2013-04-16 21 views
94

すべて ASP.NET Web APIで発生する未処理の例外をログに記録することはできますか?ASP.NET Web APIで未処理の例外をキャッチ

は、これまで私が試してみました:

  • TaskScheduler.UnobservedTaskException

に登録AppDomain.CurrentDomain.UnhandledException

  • に登録ExceptionHandlingAttribute
  • Global.asax.cs
  • Application_Errorメソッドを実装作成して登録します0正常例えば、コントローラのアクションメソッドとアクションフィルタ内でスローされた例外を処理するが、他の例外が処理されない:

    • 例外アクションメソッドによって返さIQueryableによりスロー
    • 例外の実行に失敗した場合にスローメッセージハンドラ(すなわち、コントローラのインスタンスを作成するときに例外が500内部サーバーエラーを引き起こすことが起こっている場合は、

    基本的にスローHttpConfiguration.MessageHandlers

  • 例外がクライアントに返される、私はそれをログに記録します。 Application_Errorを実装すると、Web FormsとMVCでこの仕事がうまくできました.Web APIで何が使えますか?

  • +0

    [ASP.NET Health Monitoring](http://msdn.microsoft.com/en-us/library/bb398933.aspx)を使用してみましたか?それを有効にして、例外がイベントログに記録されていないかどうかを確認してください。 –

    +0

    ヘルスモニタリングはMVCパイプライン例外をキャッチしますが、Web APIのパイプライン例外は検出されません。 –

    +0

    ありがとう - WebAPIのログ記録が既にソートされていると思ったところで、コンストラクタ/依存性注入の問題をログに記録できない理由を理解するのにしばらく時間がかかりました... – Overflew

    答えて

    126

    これは今WebAPIの2.1で可能である(What's Newを参照してください):

    IExceptionLoggerの1つのまたは複数の実装を作成します。例:次に

    public class TraceExceptionLogger : ExceptionLogger 
    { 
        public override void Log(ExceptionLoggerContext context) 
        { 
         Trace.TraceError(context.ExceptionContext.Exception.ToString()); 
        } 
    } 
    

    アプリケーションのHttpConfigurationに登録するので、などの設定コールバックの内側:

    config.Services.Add(typeof(IExceptionLogger), new TraceExceptionLogger()); 
    

    または直接:

    GlobalConfiguration.Configuration.Services.Add(typeof(IExceptionLogger), new TraceExceptionLogger()); 
    
    +1

    これはWebAPI 5.0.0では動作しないようです。 –

    +7

    @NeilBarnwellはい、Web API 2.1はSystem.Webに対応しています。HTTPアセンブリバージョン** 5.1.0 **。したがって、ここで説明するソリューションを使用するには、このバージョン以上が必要です。 [nugetパッケージのバージョン](https://www.nuget.org/packages/Microsoft.AspNet.WebApi/5.1.0)を参照してください。 – decates

    +2

    特定の500のエラーは、これによってまだ捕らえられません。 HttpException - リモートホストが接続を閉じた。 Web APIの処理以外のエラーを処理するためのglobal.asax Application_Errorの場所はまだありますか? – Avner

    17

    私自身の質問に答えるには、これは不可能です!内部サーバエラーが発生するすべての例外を処理

    は、Web APIが持つべき基本的な機能のように思えるので、私は、Web APIためグローバルエラーハンドラのためにMicrosoftとのリクエストに入れている:

    https://aspnetwebstack.codeplex.com/workitem/1001

    あなたが同意するならば、そのリンクに行き、投票してください!

    一方、優れた記事ASP.NET Web API Exception Handlingには、いくつかの異なるカテゴリのエラーをキャッチするいくつかの異なる方法が示されています。それはもっと複雑なもので、すべてサーバ間エラーを捕まえていませんが、今日利用できる最良の方法です。

    更新:グローバルエラー処理が実装され、夜間ビルドで使用できるようになりました。 ASP.NET MVC v5.1でリリースされる予定です。ここではそれが動作する方法は次のとおりです。https://aspnetwebstack.codeplex.com/wikipage?title=Global%20Error%20Handling

    +0

    Webの代わりにajax呼び出しのコントローラを使用するようですapma ..境界が既にぼやけています。もしELMAHがそれをキャプチャできれば、おそらく方法があります。 –

    +4

    Web API 2.1でグローバルエラー処理が追加されました。詳細は私の答えを見てください。 – decates

    5

    またによりグローバル例外ハンドラを作成することができますIExceptionHandlerインターフェイスを実装する(またはExceptionHandler基底クラスを継承する)。これは、すべての登録IExceptionLogger後、実行チェーンに呼び出すことが最後になります。

    IExceptionHandlerはすべて コントローラからのすべての未処理の例外を処理します。これがリストの最後です。例外が発生した場合は、 IExceptionLoggerが最初に呼び出され、コントローラー ExceptionFiltersが呼び出されますが、まだ処理されていない場合は、IExceptionHandler が実装されます。そのhere

    public class OopsExceptionHandler : ExceptionHandler 
    { 
        public override void HandleCore(ExceptionHandlerContext context) 
        { 
         context.Result = new TextPlainErrorResult 
         { 
          Request = context.ExceptionContext.Request, 
          Content = "Oops! Sorry! Something went wrong."   
         }; 
        } 
    
        private class TextPlainErrorResult : IHttpActionResult 
        { 
         public HttpRequestMessage Request { get; set; } 
    
         public string Content { get; set; } 
    
         public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken) 
         { 
          HttpResponseMessage response = 
              new HttpResponseMessage(HttpStatusCode.InternalServerError); 
          response.Content = new StringContent(Content); 
          response.RequestMessage = Request; 
          return Task.FromResult(response); 
         } 
        } 
    } 
    

    より。

    12

    Yuvalの答えは、リンクpageに記載されているように、Web APIで捕捉された未処理の例外に対する応答をカスタマイズするためのものです。詳細については、ページの「いつ使用する」セクションを参照してください。ロガーは常に呼び出されますが、応答を送信できるときだけハンドラーが呼び出されます。つまり、ログにはloggerを使用し、応答をカスタマイズするにはハンドラを使用します。

    ところで、私はアセンブリv5.2.3を使用しており、ExceptionHandlerクラスはHandleCoreメソッドを持っていません。これと同等のものはHandleだと思います。しかし、単純にサブクラス化するExceptionHandler(Yuvalの回答のように)は機能しません。私の場合は、IExceptionHandlerを次のように実装する必要があります。

    internal class OopsExceptionHandler : IExceptionHandler 
    { 
        private readonly IExceptionHandler _innerHandler; 
    
        public OopsExceptionHandler (IExceptionHandler innerHandler) 
        { 
         if (innerHandler == null) 
          throw new ArgumentNullException(nameof(innerHandler)); 
    
         _innerHandler = innerHandler; 
        } 
    
        public IExceptionHandler InnerHandler 
        { 
         get { return _innerHandler; } 
        } 
    
        public Task HandleAsync(ExceptionHandlerContext context, CancellationToken cancellationToken) 
        { 
         Handle(context); 
    
         return Task.FromResult<object>(null); 
        } 
    
        public void Handle(ExceptionHandlerContext context) 
        { 
         // Create your own custom result here... 
         // In dev, you might want to null out the result 
         // to display the YSOD. 
         // context.Result = null; 
         context.Result = new InternalServerErrorResult(context.Request); 
        } 
    } 
    

    ロガーとは異なり、追加しないでデフォルトのハンドラを置き換えることによってハンドラを登録することに注意してください。

    config.Services.Replace(typeof(IExceptionHandler), 
        new OopsExceptionHandler(config.Services.GetExceptionHandler())); 
    
    +0

    これはすばらしい解決策です。これは、「すべてのエラーをキャッチまたはロギングする」ための解決策になります。私がExceptionHandlerを拡張していたときに、どうしてそれがどうしてうまくいかなかったのか分かりませんでした。 – Rajiv

    +0

    すばらしい解決策。要求のためにMVCパイプラインがロードされると、これはうまく動作します。これまでは、startup.csでOWINをスピンアップする場合を含め、IISは引き続き例外を処理します。しかし、startup.csの処理が終了した後のある時点で、それはすばらしい仕事です。 – Gustyn

    0

    私は私の新しいglobal.asax.Application_Error方法が一貫当社のレガシーコードで未処理の例外のために呼び出されていないと思いました。

    次に、コールスタックの途中で例外テキストにResponse.Writeという名前のtry-catchブロックがいくつか見つかりました。それはそれだった。画面上にテキストをダンプし、例外の石を死んだ。