HandleErrorAttribute不起作用

时间:2012-01-24 09:12:59

标签: asp.net-mvc asp.net-mvc-3

我在VS10中启动了一个MVC 3模板项目并修改了global.asax.cs:

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
    filters.Add(new HandleErrorAttribute { ExceptionType = typeof(DivideByZeroException), View = "DivideByZeroException", Order = 1 });
    filters.Add(new HandleErrorAttribute { View = "AllOtherExceptions", Order = 2 });
}

到web.config我添加了:

<customErrors mode="On">

然后创建了相应的视图,最后在其中一个动作中添加了DivideByZero-throw。

结果:呈现了AllOtherExceptions视图。

3 个答案:

答案 0 :(得分:21)

虽然我讨厌不同意达林所说的任何事情,但他错了。

设置属性没有问题(这就是假设的方式)。

原始代码无法正常工作的唯一原因是因为您设置了Order错误。

请参阅MSDN

  

OnActionExecuting(ActionExecutingContext),   OnResultExecuting(ResultExecutingContext),和   OnAuthorization(AuthorizationContext)过滤器以正向顺序运行。   OnActionExecuted(ActionExecutedContext),   OnResultExecuting(ResultExecutingContext),和   OnException(ExceptionContext)过滤器以相反的顺序运行。

因此,您的通用AllOtherExceptions过滤器必须是最低的Order数字,而不是最高的数字。

希望下次有用。

答案 1 :(得分:8)

注册全局操作过滤器时不应设置属性。您可以编写自定义句柄错误过滤器:

public class MyHandleErrorAttribute : FilterAttribute, IExceptionFilter
{
    public void OnException(ExceptionContext filterContext)
    {
        if (!filterContext.IsChildAction && (!filterContext.ExceptionHandled && filterContext.HttpContext.IsCustomErrorEnabled))
        {
            Exception innerException = filterContext.Exception;
            if ((new HttpException(null, innerException).GetHttpCode() == 500))
            {
                var viewName = "AllOtherExceptions";
                if (typeof(DivideByZeroException).IsInstanceOfType(innerException))
                {
                    viewName = "DivideByZeroException";
                }

                string controllerName = (string)filterContext.RouteData.Values["controller"];
                string actionName = (string)filterContext.RouteData.Values["action"];
                HandleErrorInfo model = new HandleErrorInfo(filterContext.Exception, controllerName, actionName);
                ViewResult result = new ViewResult
                {
                    ViewName = viewName,
                    ViewData = new ViewDataDictionary<HandleErrorInfo>(model),
                    TempData = filterContext.Controller.TempData
                };
                filterContext.Result = result;
                filterContext.ExceptionHandled = true;
                filterContext.HttpContext.Response.Clear();
                filterContext.HttpContext.Response.StatusCode = 500;
                filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
            }
        }
    }
}

然后注册:

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

答案 2 :(得分:0)

请检查下面的恐惧答案。如果它有效,它肯定更简单。

自几周之后,这就是我的过滤器最终拼写出来的方式,使用Darins响应并将Elmah报告与来自this主题的代码结合使用。

我仍然不知道为什么你不能在全局动作过滤器上设置属性。

public class MyHandleErrorAttribute : FilterAttribute, IExceptionFilter
{
    public void OnException(ExceptionContext filterContext)
    {
        if (!filterContext.IsChildAction &&
            (!filterContext.ExceptionHandled && filterContext.HttpContext.IsCustomErrorEnabled))
        {
            var innerException = filterContext.Exception;
            if ((new HttpException(null, innerException).GetHttpCode() == 500))
            {
                var viewName = "GeneralError";
                if (typeof (HttpAntiForgeryException).IsInstanceOfType(innerException))
                    viewName = "SecurityError";

                var controllerName = (string) filterContext.RouteData.Values["controller"];
                var actionName = (string) filterContext.RouteData.Values["action"];
                var model = new HandleErrorInfo(filterContext.Exception, controllerName, actionName);
                var result = new ViewResult
                                        {
                                            ViewName = viewName,
                                            ViewData = new ViewDataDictionary<HandleErrorInfo>(model),
                                            TempData = filterContext.Controller.TempData
                                        };

                filterContext.Result = result;
                filterContext.ExceptionHandled = true;
                filterContext.HttpContext.Response.Clear();
                filterContext.HttpContext.Response.StatusCode = 500;
                filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;

 //From here on down, this is all code for Elmah-reporting.
                var version = Assembly.GetExecutingAssembly().GetName().Version;
                filterContext.Controller.ViewData["Version"] = version.ToString();

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

                LogException(e);
            }
        }
    }

    private static bool RaiseErrorSignal(Exception e)
    {
        HttpContext context = HttpContext.Current;
        if (context == null)
            return false;
        var signal = ErrorSignal.FromContext(context);
        if (signal == null)
            return false;
        signal.Raise(e, context);
        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, HttpContext.Current);

        return config.Assertion.Test(testContext);
    }

    private static void LogException(Exception e)
    {
        HttpContext context = HttpContext.Current;
        ErrorLog.GetDefault(context).Log(new Error(e, context));
    }
}