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




asp.net-mvc logging (6)

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

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

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

请注意,这可以是一个MVC路由URL,因此当发生错误时,上述内容将重定向到ErrorController.Index操作。

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

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

如何修改或如何修改属性,ELMAH可以知道出现错误并记录下来。

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


对不起,但我认为接受的答案是矫枉过正。 所有你需要做的是这样的:

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());
}

您可以通过引入一个自定义控制器工厂,将HandleErrorWithElmah属性注入到每个控制器中,从而获得上述代码并进一步推进。

有关更多信息,请参阅我的博客系列文章,了解如何登录MVC。 第一篇文章介绍让Elmah成立并运行MVC。

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

http://dotnetdarren.wordpress.com/


我是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> 

简单!


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

按照Atif Aziz的建议,我对OnException方法添加了一些修改来处理多个HandleErrorAttribute实例:

请记住,如果多个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);
}

您可以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实例有效,则可能还必须注意,重复日志记录不会发生,但上面的两个示例应该可以启动。





elmah