ASP.NET Web Apiで発生する未処理の例外をallキャッチしてログに記録するにはどうすればよいですか?
これまで私は試しました:
ExceptionHandlingAttribute
を作成して登録しますApplication_Error
にGlobal.asax.cs
メソッドを実装しますAppDomain.CurrentDomain.UnhandledException
を購読するTaskScheduler.UnobservedTaskException
を購読するExceptionHandlingAttribute
は、コントローラーアクションメソッドおよびアクションフィルター内でスローされた例外を正常に処理しますが、他の例外は処理されません。例:
IQueryable
の実行に失敗した場合にスローされる例外HttpConfiguration.MessageHandlers
)基本的に、例外によって500内部サーバーエラーがクライアントに返される場合、ログに記録する必要があります。 Application_Error
を実装すると、この仕事はWebフォームとMVCでうまくいきました。WebApiで何が使えますか?
これはWebAPI 2.1で可能になりました( 新機能 を参照):
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());
Yuvalの答えは、リンクされた page に記載されているように、ロギングではなく、Web APIによってキャッチされた未処理の例外に対する応答をカスタマイズすることです。詳細については、ページの「いつ使用するか」セクションを参照してください。ロガーは常に呼び出されますが、ハンドラーは応答を送信できる場合にのみ呼び出されます。要するに、 logger を使用してログを記録し、ハンドラーを使用して応答をカスタマイズします。
ところで、私はAssembly v5.2.3を使用しており、 ExceptionHandler
クラスにはHandleCore
メソッドがありません。相当するのは、Handle
です。ただし、(Yuvalの答えのように)ExceptionHandler
をサブクラス化するだけでは機能しません。私の場合、次のように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()));
私自身の質問に答えるために、これは不可能です!
内部サーバーエラーの原因となるすべての例外の処理は、Web APIが持つべき基本的な機能のように思えるので、MicrosoftにWeb APIのグローバルエラーハンドラー:
https://aspnetwebstack.codeplex.com/workitem/1001
同意したら、そのリンクにアクセスして投票してください!
それまでの間、優れた記事 ASP.NET Web API例外処理 は、いくつかの異なるカテゴリのエラーをキャッチするいくつかの異なる方法を示しています。それは本来よりも複雑であり、allインターナルサーバーエラーをキャッチしませんが、今日利用可能な最良のアプローチです。
更新:グローバルエラー処理が実装され、ナイトリービルドで利用可能になりました! ASP.NET MVC v5.1でリリースされます。仕組みは次のとおりです。 https://aspnetwebstack.codeplex.com/wikipage?title=Global%20Error%20Handling
IExceptionHandler
インターフェイスを実装する(またはExceptionHandler
基本クラスを継承する)ことにより、グローバル例外ハンドラーを作成することもできます。すべての登録済みIExceptionLogger
の後、実行チェーンで最後に呼び出されます。
IExceptionHandlerは、すべてのコントローラーからのすべての未処理の例外を処理します。これはリストの最後です。例外が発生した場合、IExceptionLoggerが最初に呼び出され、次にコントローラーExceptionFiltersが呼び出され、まだ処理されない場合はIExceptionHandler実装が呼び出されます。
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);
}
}
}
詳細は こちら です。
私の新しいglobal.asax.Application_Error
メソッドは、レガシーコードの未処理の例外に対して一貫して呼び出されていないと思っていました。
次に、コールスタックの途中で、ExceptionテキストでResponse.Writeを呼び出したtry-catchブロックをいくつか見つけました。それでした。画面上のテキストをダンプし、例外の石を殺しました。