[解決済み] C# MVC4 WebAPIアプリのすべての例外をグローバルに記録するにはどうすればよいですか?
質問
背景
私は顧客のためにAPIサービスレイヤーを開発しており、すべてのエラーをグローバルにキャッチしてログに残すよう要求されました。
未知のエンドポイント (またはアクション) のようなものは、ELMAH を使用するか、または以下のようなものを
Global.asax
:
protected void Application_Error()
{
Exception unhandledException = Server.GetLastError();
//do more stuff
}
. .ルーティングに関連しない未処理エラーはログに残りません。 例えば
public class ReportController : ApiController
{
public int test()
{
var foo = Convert.ToInt32("a");//Will throw error but isn't logged!!
return foo;
}
}
を設定することも試してみました。
[HandleError]
属性は、このフィルタを登録することで、グローバルに利用することができます。
filters.Add(new HandleErrorAttribute());
しかし、これもすべてのエラーを記録するわけではありません。
問題点・質問
を呼び出すと発生するようなエラーをどのように遮断すればよいのでしょうか?
/test
ログを取ることができますか? この答えは明白であるべきだと思われますが、私はこれまで思いつく限りのことをすべて試してきました。
理想は、エラーログに、要求したユーザーのIPアドレス、日時などを追加することです。 また、エラーが発生したときに、自動的にサポートスタッフにメールを送ることができるようにしたいです。 エラーが発生したときにそれを阻止することさえできれば、これらすべてを実現することができます。
解決しました!
Darin Dimitrovの回答を受けて、この問題を解決することができました。 WebAPIは ではなく は、通常の MVC コントローラと同じようにエラーを処理します。
以下はうまくいったものです。
1) ネームスペースにカスタムフィルターを追加します。
public class ExceptionHandlingAttribute : ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext context)
{
if (context.Exception is BusinessException)
{
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.InternalServerError)
{
Content = new StringContent(context.Exception.Message),
ReasonPhrase = "Exception"
});
}
//Log Critical errors
Debug.WriteLine(context.Exception);
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.InternalServerError)
{
Content = new StringContent("An error occurred, please try again or contact the administrator."),
ReasonPhrase = "Critical Exception"
});
}
}
2) 次に、このフィルターをグローバルに登録するために WebApiConfig クラスがあります。
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute("DefaultApi", "api/{controller}/{action}/{id}", new { id = RouteParameter.Optional });
config.Filters.Add(new ExceptionHandlingAttribute());
}
}
または
を使用すると、登録を省略し、単一のコントローラを
[ExceptionHandling]
属性で指定します。
解決方法は?
<ストライク
Web APIがASP.NETアプリケーションの中でホストされている場合、そのAPIを使用するために
Application_Error
イベントは、あなたが示したテストアクションの例外を含む、あなたのコード内のすべての未処理の例外に対して呼び出されます。ですから、この例外は Application_Error イベントの中で処理すればよいのです。このサンプルコードでは、例外の型が
HttpException
というのは明らかに違うのですが
Convert.ToInt32("a")
のコードを使用します。ですから、そこではすべての例外を記録し、処理するようにしてください。
protected void Application_Error()
{
Exception unhandledException = Server.GetLastError();
HttpException httpException = unhandledException as HttpException;
if (httpException == null)
{
Exception innerException = unhandledException.InnerException;
httpException = innerException as HttpException;
}
if (httpException != null)
{
int httpCode = httpException.GetHttpCode();
switch (httpCode)
{
case (int)HttpStatusCode.Unauthorized:
Response.Redirect("/Http/Error401");
break;
// TODO: don't forget that here you have many other status codes to test
// and handle in addition to 401.
}
else
{
// It was not an HttpException. This will be executed for your test action.
// Here you should log and handle this case. Use the unhandledException instance here
}
}
}
<ストライク
Web APIにおける例外処理は、様々なレベルで行うことが可能です。ここでは
detailed article
を説明します。
-
グローバルな例外フィルタとして登録可能なカスタム例外フィルタ属性
[AttributeUsage(AttributeTargets.All)] public class ExceptionHandlingAttribute : ExceptionFilterAttribute { public override void OnException(HttpActionExecutedContext context) { if (context.Exception is BusinessException) { throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.InternalServerError) { Content = new StringContent(context.Exception.Message), ReasonPhrase = "Exception" }); } //Log Critical errors Debug.WriteLine(context.Exception); throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.InternalServerError) { Content = new StringContent("An error occurred, please try again or contact the administrator."), ReasonPhrase = "Critical Exception" }); } }
-
カスタムアクションの呼び出し元
public class MyApiControllerActionInvoker : ApiControllerActionInvoker { public override Task<HttpResponseMessage> InvokeActionAsync(HttpActionContext actionContext, System.Threading.CancellationToken cancellationToken) { var result = base.InvokeActionAsync(actionContext, cancellationToken); if (result.Exception != null && result.Exception.GetBaseException() != null) { var baseException = result.Exception.GetBaseException(); if (baseException is BusinessException) { return Task.Run<HttpResponseMessage>(() => new HttpResponseMessage(HttpStatusCode.InternalServerError) { Content = new StringContent(baseException.Message), ReasonPhrase = "Error" }); } else { //Log critical error Debug.WriteLine(baseException); return Task.Run<HttpResponseMessage>(() => new HttpResponseMessage(HttpStatusCode.InternalServerError) { Content = new StringContent(baseException.Message), ReasonPhrase = "Critical Error" }); } } return result; } }
関連
-
[解決済み】「The breakpoint will not currently be hit」を改善するには?このドキュメントにはシンボルが読み込まれていません。" という警告はどうすれば改善されますか?
-
[解決済み】Ajax処理で「無効なJSONプリミティブ」と表示される件
-
[解決済み】ソケットのアドレス(プロトコル/ネットワークアドレス/ポート)は、通常1つしか使用できない?
-
[解決済み】値をNULLにすることはできません。パラメータ名:source
-
[解決済み】画像のペイントにTextureBrushを使用する方法
-
[解決済み】データが存在しないのに読み込もうとする試みが無効である
-
[解決済み] 検索」からすべての「permission denied」メッセージを除外するにはどうすればよいですか?
-
[解決済み] ディレクトリ内のすべてのファイルやフォルダを削除する方法は?
-
[解決済み] すべてのサーバーサイドのコードでConfigureAwaitを呼び出すためのベストプラクティス
-
[解決済み】WPFアプリケーションで例外をグローバルにキャッチする?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】パディングが無効で、削除できない?
-
[解決済み】取り消せないメンバはメソッドのように使えない?
-
[解決済み】C# - パスに不正な文字がある場合
-
[解決済み】2年前のMSDateを把握する【クローズド
-
[解決済み] 関数を終了するには?
-
[解決済み】「namespace」なのに「type」のように使われる。
-
[解決済み】プロセスが実行されているかどうかを知るには?
-
[解決済み】Microsoft.Extensions.LoggingからILoggerを解決することができない
-
[解決済み】データが存在しないのに読み込もうとする試みが無効である
-
[解決済み】スレッド終了またはアプリケーションの要求により、I/O操作が中断されました。