【问题标题】:HandleErrorAttribute not workingHandleErrorAttribute 不起作用
【发布时间】:2012-02-17 13:11:22
【问题描述】:

我已经在 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 被渲染。

【问题讨论】:

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


    【解决方案1】:

    尽管我讨厌不同意达林所说的任何话,但他在这一点上错了。

    设置属性没有问题(这是您应该这样做的方式)。

    您的原始代码未按预期工作的唯一原因是您的 Order 设置错误。

    MSDN:

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

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

    希望对下次有帮助。

    【讨论】:

    • 听起来你有案子,害怕!既然达林确实解决了我的问题,你就必须用赞成票来解决这个问题。
    • 谢谢你 - 应该是答案!
    • 有趣的是,如果我执行 DivisonByZero 之类的异常,则会触发过滤器,但不会针对这种特定类型的异常 stackoverflow.com/questions/70078533/…。有什么线索吗?
    【解决方案2】:

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

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

    【讨论】:

    • 它当然有效。为什么注册全局动作过滤器时不能设置属性?
    【解决方案3】:

    请检查下面恐惧的答案。如果可行的话,肯定会更简单。

    几周后,这就是我的过滤器最终拼写出来的方式,使用 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));
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2012-02-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-30
      • 2011-10-01
      相关资源
      最近更新 更多