你可以子类化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;
}
}
第二个版本将尝试使用错误信号首先从 ELMAH 开始,其中涉及完全配置的管道,如日志记录、邮件、过滤等等。如果失败,它会尝试查看是否应过滤该错误。如果不是,则仅记录错误。此实现不处理邮件通知。如果可以发出异常信号,则将发送一封邮件(如果已配置)。
您可能还需要注意,如果有多个HandleErrorAttribute
实例有效,则不会发生重复日志记录,但上面的两个示例应该可以帮助您入门。