如何让ELMAH使用ASP.NET MVC [HandleError]属性?

こ雲淡風輕ζ 提交于 2020-01-08 19:26:53

【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>

我正在尝试使用ELMAH来记录我的ASP.NET MVC应用程序中的错误,但是当我在控制器上使用[HandleError]属性时,ELMAH在发生错误时不会记录任何错误。

正如我猜测它,因为ELMAH只记录未处理的错误,[HandleError]属性正在处理错误,因此无需记录它。

我如何修改或如何修改属性,以便ELMAH可以知道有错误并记录它..

编辑:让我确保每个人都理解,我知道我可以修改那个不是我问的问题的属性... ELMAH在使用handleerror属性时会被绕过,这意味着它不会看到有错误因为它被处理了已经由属性...我要问的是有一种方法让ELMAH看到错误并记录它即使属性处理它...我搜索周围,没有看到任何方法调用强制它来记录错误....


#1楼

现在NuGet中有一个ELMAH.MVC包,其中包括Atif的改进解决方案以及处理MVC路由中的elmah接口的控制器(不再需要使用该axd)
该解决方案(以及此处的所有解决方案)的问题在于,elmah错误处理程序实际上是以某种方式处理错误,忽略了您可能想要设置为customError标记或通过ErrorHandler或您自己的错误处理程序
最好的解决方案是IMHO创建一个过滤器,它将在所有其他过滤器的末尾起作用,并记录已经处理过的事件。 elmah模块应该注意记录应用程序未处理的其他错误。 这还允许您使用运行状况监视器和可添加到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());
    }

请注意,我在那里留下了一个注释,提醒人们如果他们想要添加一个实际处理异常的全局过滤器,它应该在最后一个过滤器之前进行,否则你会遇到ElmahMVCErrorFilter忽略未处理异常的情况,因为它没有被处理,它应该由Elmah模块提供,但是接下来的过滤器将异常标记为已处理,模块忽略它,导致异常从未使它成为elmah。

现在,确保webconfig中的elmah appsettings看起来像这样:

<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记录这些错误,通过elmah模块向web.config添加customError配置,甚至编写自己的错误处理程序。 您唯一需要做的就是记住在我们编写的elmah过滤器之前不添加任何实际处理错误的过滤器。 我忘了提到:elmah没有重复。


#2楼

一个完全替代的解决方案是不使用MVC HandleErrorAttribute ,而是依赖于Elmah旨在使用的ASP.Net错误处理。

您需要从App_Start \\ FilterConfig(或Global.asax)中删除默认的全局HandleErrorAttribute ,然后在Web.config中设置错误页面:

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

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


#3楼

您可以采用上面的代码,并通过引入一个自定义控制器工厂更进一步,该工厂将HandleErrorWithElmah属性注入每个控制器。

有关更多信息,请查看我关于登录MVC的博客系列。 第一篇文章介绍了如何让Elmah为MVC设置和运行。

本文末尾有一个可下载代码的链接。 希望有所帮助。

http://dotnetdarren.wordpress.com/


#4楼

这正是我的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);
}

#5楼

对我来说,让电子邮件日志记录工作非常重要。 经过一段时间后,我发现在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);
        [...]
    }
    [...]
}

我希望这会帮助别人:)

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!