ASP.net MVC - 自定义HandleError过滤器 - 根据异常类型指定视图

时间:2011-11-15 23:37:11

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

我在MVC应用程序中继承HandleErrorAttribute,因此我可以记录错误:

public class HandleAndLogErrorAttribute : HandleErrorAttribute
{
    public override void OnException(ExceptionContext filterContext)
    {
        base.OnException(filterContext);

        if( filterContext.Exception != null )
        {
            // log here
        }
    }
}

我将其添加为全局过滤器:

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

是否可以为特定的异常类型指定自定义视图?例如:

if( filterContext.Exception is DivideByZeroException )
{
    // how do i specify that the view should be DivideByZero?
}

1 个答案:

答案 0 :(得分:73)

  1. 创建一个继承HandleErrorAttribute的新过滤器(或直接实现IExceptionFilter)
  2. 在global.asax中注册(通过替换filters.Add(new HandleError());):
  3. 这是我创建的一个过滤器,它尝试根据特定的HTTP状态代码查找视图:

    public class MyErrorHandler : FilterAttribute, IExceptionFilter
    {
        public void OnException(ExceptionContext filterContext)
        {
            if (filterContext.ExceptionHandled || !filterContext.HttpContext.IsCustomErrorEnabled)
                return;
    
            var statusCode = (int) HttpStatusCode.InternalServerError;
            if (filterContext.Exception is HttpException)
            {
                statusCode = filterContext.Exception.As<HttpException>().GetHttpCode();
            }
            else if (filterContext.Exception is UnauthorizedAccessException)
            {
                //to prevent login prompt in IIS
                // which will appear when returning 401.
                statusCode = (int)HttpStatusCode.Forbidden; 
            }
            _logger.Error("Uncaught exception", filterContext.Exception);
    
            var result = CreateActionResult(filterContext, statusCode);
            filterContext.Result = result;
    
            // Prepare the response code.
            filterContext.ExceptionHandled = true;
            filterContext.HttpContext.Response.Clear();
            filterContext.HttpContext.Response.StatusCode = statusCode;
            filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
        }
    
        protected virtual ActionResult CreateActionResult(ExceptionContext filterContext, int statusCode)
        {
            var ctx = new ControllerContext(filterContext.RequestContext, filterContext.Controller);
            var statusCodeName = ((HttpStatusCode) statusCode).ToString();
    
            var viewName = SelectFirstView(ctx,
                                           "~/Views/Error/{0}.cshtml".FormatWith(statusCodeName),
                                           "~/Views/Error/General.cshtml",
                                           statusCodeName,
                                           "Error");
    
            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),
                             };
            result.ViewBag.StatusCode = statusCode;
            return result;
        }
    
        protected string SelectFirstView(ControllerContext ctx, params string[] viewNames)
        {
            return viewNames.First(view => ViewExists(ctx, view));
        }
    
        protected bool ViewExists(ControllerContext ctx, string name)
        {
            var result = ViewEngines.Engines.FindView(ctx, name, null);
            return result.View != null;
        }
    }