如何让ELMAH与ASP.NET MVC [HandleError]属性一起工作?

 2023-02-17    428  

问题描述

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

因为我猜测它因为Elmah只记录未处理的错误,并且[HanderError]属性正在处理错误,因此无需记录它.

如何让ELMAH与ASP.NET MVC [HandleError]属性一起工作?

如何修改或如何修改属性,因此Elmah可以知道出错并记录它..

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

推荐答案

您可以子类 HandleErrorAttribute 并覆盖其http://msdn.microsoft.com/en-us/library/system.web.mvc.handleerrorattribute.onexception.aspx” rel=”noreferrer”nn 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的改进解决方案,也包括处理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.

现在,确保elmah在webconfig中的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.disableHandHleerRerfilter”,如果这是假的,它将使用Elmah.MVC中的处理程序,实际上使用默认的HanderErrorHandler将忽略您的CustomError设置

此设置允许您在类和视图中设置自己的ErrorHandler标签,同时仍通过ElmahmvcErrorFilter记录这些错误,将CustomError配置添加到Web.config通过Elmah模块,甚至编写自己的错误处理程序.您唯一需要做的是请不要添加任何将在我们写入的ELMAH过滤器之前实际处理错误的过滤器.我忘了提到:在Elmah中没有重复.

以上所述是小编给大家介绍的如何让ELMAH与ASP.NET MVC [HandleError]属性一起工作?,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对77isp云服务器技术网的支持!

原文链接:https://77isp.com/post/34177.html

=========================================

https://77isp.com/ 为 “云服务器技术网” 唯一官方服务平台,请勿相信其他任何渠道。