ELMAH を使用して ASP.NET MVC アプリケーションでエラーをログに記録しようとしていますが、コントローラーで [HandleError] 属性を使用すると、ELMAH はエラーが発生してもログに記録しません。
私の推測では、ELMAH は未処理のエラーのみをログに記録し、[HandleError] 属性がエラーを処理するため、ログに記録する必要がないためです。
ELMAH がエラーがあったことを認識してログに記録できるように、属性を変更する方法、または変更するにはどうすればよいでしょうか。
編集:皆さんに理解していただくために、属性を変更できることはわかっていますが、それは私が尋ねている質問ではありません... handleerror 属性を使用すると ELMAH はバイパスされます。つまり、属性によってエラーがすでに処理されているため、エラーがあったことを認識しません... 私が尋ねているのは、属性がエラーを処理した場合でも、ELMAH にエラーを認識してログに記録させる方法があるかどうかです... 検索してみましたが、エラーをログに記録するように強制するために呼び出すメソッドは見つかりませんでした...
ベストアンサー1
サブクラス化できるHandleErrorAttribute
そしてそれを上書きするOnException
メンバー (コピーする必要はありません) を作成し、ELMAH で例外をログに記録し、基本実装が例外を処理する場合にのみログに記録します。必要な最小限のコードは次のとおりです。
using System.Web.Mvc;
using Elmah;
public class HandleErrorAttribute : System.Web.Mvc.HandleErrorAttribute
{
public override void OnException(ExceptionContext context)
{
base.OnException(context);
if (!context.ExceptionHandled)
return;
var httpContext = context.HttpContext.ApplicationInstance.Context;
var signal = ErrorSignal.FromContext(httpContext);
signal.Raise(context.Exception, httpContext);
}
}
最初に基本実装が呼び出され、例外を処理中としてマークする機会が与えられます。その後にのみ、例外が通知されます。上記のコードは単純ですが、HttpContext
テストなど、が利用できない環境で使用すると問題が発生する可能性があります。その結果、より防御的なコードが必要になります (少し長くなりますが)。
using System.Web;
using System.Web.Mvc;
using Elmah;
public class HandleErrorAttribute : System.Web.Mvc.HandleErrorAttribute
{
public override void OnException(ExceptionContext context)
{
base.OnException(context);
if (!context.ExceptionHandled // if unhandled, will be logged anyhow
|| TryRaiseErrorSignal(context) // prefer signaling, if possible
|| IsFiltered(context)) // filtered?
return;
LogException(context);
}
private static bool TryRaiseErrorSignal(ExceptionContext context)
{
var httpContext = GetHttpContextImpl(context.HttpContext);
if (httpContext == null)
return false;
var signal = ErrorSignal.FromContext(httpContext);
if (signal == null)
return false;
signal.Raise(context.Exception, httpContext);
return true;
}
private static bool IsFiltered(ExceptionContext context)
{
var config = context.HttpContext.GetSection("elmah/errorFilter")
as ErrorFilterConfiguration;
if (config == null)
return false;
var testContext = new ErrorFilterModule.AssertionHelperContext(
context.Exception,
GetHttpContextImpl(context.HttpContext));
return config.Assertion.Test(testContext);
}
private static void LogException(ExceptionContext context)
{
var httpContext = GetHttpContextImpl(context.HttpContext);
var error = new Error(context.Exception, httpContext);
ErrorLog.GetDefault(httpContext).Log(error);
}
private static HttpContext GetHttpContextImpl(HttpContextBase context)
{
return context.ApplicationInstance.Context;
}
}
この2番目のバージョンでは、エラーシグナリングまず ELMAH から、ログ記録、メール送信、フィルタリングなどの完全に構成されたパイプラインが実行されます。それが失敗した場合は、エラーをフィルタリングする必要があるかどうかを確認しようとします。そうでない場合は、エラーは単にログに記録されます。この実装ではメール通知は処理されません。例外を通知できる場合は、メールが送信されます (そのように構成されている場合)。
HandleErrorAttribute
複数のインスタンスが有効な場合は重複したログ記録が発生しないように注意する必要もありますが、上記の 2 つの例を参考にして作業を開始してください。