logging - 如何使ELMAH ASP.Net MVC [HandleError]属性呢?

  显示原文与译文双语对照的内容

我试图用ELMAH日志中的错误我 ASP.NET mvc应用程序,然而当我在控制器使用 [HandleError] 属性ELMAH不记录任何错误发生时。

因为ELMAH只记录未处理的错误,[HandleError] 属性正在处理错误,所以不需要记录它。

如何修改或者如何修改属性,以便ELMAH能够知道有一个错误,并记录它。

收费: 让我确定大家都明白,我知道我可以修改不是我要求的问题。 使用handleerror属性时,ELMAH会被绕过,这意味着它将不会看到出现错误,因为它已经被属性处理。 我要求的是一种方法,使ELMAH看到错误,并记录它,即使属性处理它。我四处搜索并没有任何方法来强制它记录错误。。

时间:

你可以子类化 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 实例实际上是有效的,那么重复的日志不会发生,但是上面两个示例应该得到你的开始。

抱歉,我认为接受的答案是一个多余的。 你需要做的就是:


public class ElmahHandledErrorLoggerFilter : IExceptionFilter
{
 public void OnException (ExceptionContext context)
 {
//Log only handled exceptions, because all other will be caught by ELMAH anyway.
 if (context.ExceptionHandled)
 ErrorSignal.FromCurrentContext().Raise(context.Exception);
 }
}

然后注册( 顺序很重要) Global.asax. cs:


public static void RegisterGlobalFilters (GlobalFilterCollection filters)
{
 filters.Add(new ElmahHandledErrorLoggerFilter());
 filters.Add(new HandleErrorAttribute());
}

现在nuget ELMAH.MVC 包中包括一种改进解决方案,Atif和控制器处理elmah接口在mvc路由(不需要使用axd了)
问题解决方案( 所有这些都在这里) 是这样或那样的方式elmah错误处理程序是处理错误,忽略你可能想要建立customerror标记或通过errorhandler或自己的错误处理程序
imho最好的解决方案是创建一个过滤器,它将结束时,所有其他的过滤器和已处理的事件日志。 elmah模块应该负责loging的其他错误,这些错误由应用程序处理。 这也允许你使用健康监视器以及可以添加到 ASP.NET 中的所有其他模块来查看错误事件

我在 elmah.mvc 内的ErrorHandler中使用反射器编写了这个


public class ElmahMVCErrorFilter : IExceptionFilter
{
 private static ErrorFilterConfiguration _config;

 public void OnException(ExceptionContext context)
 {
 if (context.ExceptionHandled)//The unhandled ones will be picked by the elmah module
 {
 var e = context.Exception;
 var context2 = context.HttpContext.ApplicationInstance.Context;
//TODO: Add additional variables to context.HttpContext.Request.ServerVariables for both handled and unhandled exceptions
 if ((context2 == null) || (!_RaiseErrorSignal(e, context2) &&!_IsFiltered(e, context2)))
 {
 _LogException(e, context2);
 }
 }
 }

 private static bool _IsFiltered(System.Exception e, System.Web.HttpContext context)
 {
 if (_config == null)
 {
 _config = (context.GetSection("elmah/errorFilter") as ErrorFilterConfiguration)?? new ErrorFilterConfiguration();
 }
 var context2 = new ErrorFilterModule.AssertionHelperContext((System.Exception)e, context);
 return _config.Assertion.Test(context2);
 }

 private static void _LogException(System.Exception e, System.Web.HttpContext context)
 {
 ErrorLog.GetDefault((System.Web.HttpContext)context).Log(new Elmah.Error((System.Exception)e, (System.Web.HttpContext)context));
 }


 private static bool _RaiseErrorSignal(System.Exception e, System.Web.HttpContext context)
 {
 var signal = ErrorSignal.FromContext((System.Web.HttpContext)context);
 if (signal == null)
 {
 return false;
 }
 signal.Raise((System.Exception)e, (System.Web.HttpContext)context);
 return true;
 }
}

现在,在你的过滤器配置中,你需要执行如下操作:


 public static void RegisterGlobalFilters(GlobalFilterCollection filters)
 {
//These filters should go at the end of the pipeline, add all error handlers before
 filters.Add(new ElmahMVCErrorFilter());
 }

异常的相关从不造Elmah来注意,我后面留了一个回复要提醒用户,如果他们想添加一个全局过滤器有这种真正处理该异常就需要去这最后一个筛选器之前,否则你运行到这种情况在ElmahMVCErrorFilter并且视未处理的异常将被忽略,因为它表示不处理,它应该是由Elmah模块,但该模块然后下一个筛选器标记为已经处理的异常并忽略这些代码

现在,确保elmah的appsettingswebconfig看起来像这样:


<add key="elmah.mvc.disableHandler" value="false"/> <!-- This handles elmah controller pages, if disabled elmah pages will not work -->
<add key="elmah.mvc.disableHandleErrorFilter" value="true"/> <!-- This uses the default filter for elmah, set to disabled to use our own -->
<add key="elmah.mvc.requiresAuthentication" value="false"/> <!-- Manages authentication for elmah pages -->
<add key="elmah.mvc.allowedRoles" value="*"/> <!-- Manages authentication for elmah pages -->
<add key="elmah.mvc.route" value="errortracking"/> <!-- Base route for elmah pages -->

最重要的一个是" elmah.mvc.disablehandleerrorfilter",如果这是假的它将使用处理程序内部 ELMAH.MVC 会处理的异常使用默认HandleErrorHandler忽略customerror设置

这个设置允许你设置自己的errorhandler标记类和观点,同时还通过 ElmahMVCErrorFilter loging那些错误,customerror配置添加到 Web.Config elmah模块,甚至编写自己的错误处理程序。 你唯一需要做的就是记住不要添加任何过滤器elmah过滤器之前会处理错误的写。 而我却忘记了: elmah中没有重复项。

我在 ASP.NET MVC中是新的。 我遇到了同样的问题,下面是我在 Erorr.vbhtml 中的操作( 如果你只需要使用Elmah日志记录这个错误,它就可以工作)


@ModelType System.Web.Mvc.HandleErrorInfo

 @Code
 ViewData("Title") ="Error"
 Dim item As HandleErrorInfo = CType(Model, HandleErrorInfo)
//To log error with Elmah
 Elmah.ErrorLog.GetDefault(HttpContext.Current).Log(New Elmah.Error(Model.Exception, HttpContext.Current))
 End Code

<h2>
 Sorry, an error occurred while processing your request.<br/>

 @item.ActionName<br/>
 @item.ControllerName<br/>
 @item.Exception.Message
</h2> 

它只是 !

对我来说,获取电子邮件日志非常重要。 一段时间后,我发现,这只需要在 Atif 2行代码更多的例子。


public class HandleErrorWithElmahAttribute : HandleErrorAttribute
{
 static ElmahMVCMailModule error_mail_log = new ElmahMVCMailModule();

 public override void OnException(ExceptionContext context)
 {
 error_mail_log.Init(HttpContext.Current.ApplicationInstance);
 [...]
 }
 [...]
}

我希望这对某人有帮助:

完全替代的解决方案是不使用 MVC HandleErrorAttribute,而是依靠 ASP.NET 错误处理,而Elmah是设计用来处理。

你需要删除默认全球 HandleErrorAttribute App_StartFilterConfig ( 或者 global.asax ), 然后在你的Web.config :建立一个错误页面


<customErrors mode="RemoteOnly" defaultRedirect="~/error/"/>

注意,这可以是一个MVC路由的URL,因此当发生错误时,上面的代码会重定向到 ErrorController.Index 操作。

这正是我的MVC站点配置所需要的 !

我在 OnException 方法中添加了一些修改来处理多个 HandleErrorAttribute 实例,如 Atif Aziz建议的那样:

记住,如果有多个 HandleErrorAttribute 实例生效,那么重复的日志不会发生。

我只是在调用基类之前检查 context.ExceptionHandled,只是想知道是否有人在当前处理程序之前处理了异常。
它为我工作,我发布代码以防别人需要它,并询问是否有人知道我是否忽略了任何东西。

希望它有用:


public override void OnException(ExceptionContext context)
{
 bool exceptionHandledByPreviousHandler = context.ExceptionHandled;

 base.OnException(context);

 Exception e = context.Exception;
 if (exceptionHandledByPreviousHandler
 ||!context.ExceptionHandled//if unhandled, will be logged anyhow
 || RaiseErrorSignal(e)//prefer signaling, if possible
 || IsFiltered(context))//filtered?
 return;

 LogException(e);
}

...