HandleErrorAttribute not working

前端 未结 3 1685
余生分开走
余生分开走 2020-12-18 05:58

I have started an MVC 3 template project in VS10 and modified global.asax.cs as such:

public static void RegisterGlobalFilters(GlobalFilterCollection filters         


        
相关标签:
3条回答
  • 2020-12-18 06:24

    You shouldn't set properties when registering a global action filter. You could write a custom handle error filter:

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

    and then register it:

    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new MyHandleErrorAttribute());
    }
    
    0 讨论(0)
  • 2020-12-18 06:34

    Much though I hate to disagree with anything Darin says, he is wrong on this one.

    There is no problem with setting the properties (that's the way you are supposed to do it).

    The only reason your original code didn't work as expected is because you have the Order set wrong.

    See MSDN:

    The OnActionExecuting(ActionExecutingContext), OnResultExecuting(ResultExecutingContext), and OnAuthorization(AuthorizationContext) filters run in forward order. The OnActionExecuted(ActionExecutedContext), OnResultExecuting(ResultExecutingContext), and OnException(ExceptionContext) filters run in reverse order.

    So your generic AllOtherExceptions filter needs to be the lowest Order number, not the highest.

    Hopefully that helps for next time.

    0 讨论(0)
  • 2020-12-18 06:36

    Do check fear's answer below. It's certainly the simpler, if it works.

    Since it came after a few weeks, this is how my filter finally spelled out, using Darins response and incorporating Elmah-reporting, with code from this topic.

    I still don't know why you can't set properties on a global action filter.

    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));
        }
    }
    
    0 讨论(0)
提交回复
热议问题