ASP.NET MVC 自定义错误页面心得

自定义错误页面的目的,就是为了能让程序在出现错误/异常的时候,能够有较好的显示体验。

所以,首先要先了解,我们可以在哪里捕获异常。

当程序发生错误的时候,我们可以在两个地方捕获:

  1. Global里面的Application_Error 。
  2. HandleErrorAttribute 中的OnException。(需要新建一个类,继承HandleErrorAttribute)

那我们到底应该在哪里处理错误好呢?下面我来给大家说说他们的区别。

Application_Error

程序中发生的所有异常,都可以在这里捕获。但是有一个不足的地方,那就是,如果我们在这里捕获异常之后,需要显示错误页面,那么浏览器上的地址是会改变的,已经被重定向了。也就是说,浏览器上显示的地址,并不是真正发生错误的地址,而是仅仅是显示错误信息的页面地址。这个不足,跟在Web.config的customError中配置错误页面是一样的。

很多时候,我们是希望在访问某个URL后发生了错误,显示错误页面之后,URL还是不变。因此,在这里处理异常并不能满足这种需求。

OnException。(继承HandleErrorAttribute)

MVC的特点就是,每一个请求都对应一个Controller,当在某个Controller中发生异常时,我们都可以在OnException中捕获。但是,如果根本就找不到这个Controller,那么这种错误OnException就无能为力了。举个例子:

假设有个Controller叫About,当访问http://host/About/Index发生错误时,是可以在OnException中捕获的。但如果我访问http://host/Aboute/Index的时候,因为根本不存在Aboute控制器,所以这种错误是无法在OnException捕获的,如果要捕获这种错误,只能在Application_Error中处理。虽然OnException不能捕获所有的错误,但是,它可以解决Application_Error错误页面重定向的问题,在显示错误页面的时候,URL保持不变。

 

执行顺序

如果发生了错误,会先执行OnException,如果设置 filterContext.ExceptionHandled = true; 则说明该错误已被处理,不会再执行Application_Error,否则会继续执行Application_Error。

 

参考代码

 protected void Application_Error(Object sender, EventArgs e)
        {
            //当路径出错,无法找到控制器时,不会执行FilterConfig中的OnException,而会在这里捕获。
            //当发生404错误时,执行完OnException后,还会执行到这里。
            //当发生其他错误,会执行OnException,但在base.OnException中已经处理完错误,不会再到这里执行。
            var lastError = Server.GetLastError();
            if (lastError != null)
            {
                var httpError = lastError as HttpException;

                if (httpError != null)
                {
                    //Server.ClearError();
                    switch (httpError.GetHttpCode())
                    {
                        case 404:
                            Response.Redirect("/Views/Static/404.html");
                            break;
                    }
                }
            }
}

 

    [AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = false)]
    public class LogExceptionAttribute : HandleErrorAttribute
    {
        public override void OnException(ExceptionContext filterContext)
        {
            string controllerName = (string)filterContext.RouteData.Values["controller"];
            string actionName = (string)filterContext.RouteData.Values["action"];
            HandleErrorInfo info = new HandleErrorInfo(filterContext.Exception, controllerName, actionName);

            HttpRequestBase request = filterContext.RequestContext.HttpContext.Request;
            string broser = request.Browser.Browser;
            string broserVersion = request.Browser.Version;
            string system = request.Browser.Platform;
            string errBaseInfo = string.Format("UserId={0},Broser={1},BroserVersion={2},System={3},Controller={4},Action={5}", AuthAttribute.GetUserId(), broser, broserVersion, system, controllerName, actionName);
            LogUtil.Error(errBaseInfo, filterContext.Exception, Website.LOG_ID);

            if (!filterContext.ExceptionHandled)
            {
                if (filterContext.HttpContext.IsCustomErrorEnabled)
                {
                    filterContext.HttpContext.Response.Clear();
                    HttpException httpex = filterContext.Exception as HttpException;
                    if (httpex != null)
                    {
                        filterContext.HttpContext.Response.StatusCode = httpex.GetHttpCode();
                        // info = new HandleErrorInfo(ex, controllerName, actionName);
                        //switch (httpex.GetHttpCode())
                        //{
                        //    case 403:
                        //        break;
                        //    case 404:
                        //        break;
                        //    default:
                        //        base.OnException(filterContext);
                        //        break;
                        //}
                    }
                    else
                    {
                        filterContext.HttpContext.Response.StatusCode = 500;
                    }

                    filterContext.Result = new ViewResult() { ViewName = "/Views/Shared/Error.cshtml", ViewData = new ViewDataDictionary<HandleErrorInfo>(info) };
                    filterContext.ExceptionHandled = true;
                    filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
                }
                else
                {
                    //base.OnException(filterContext);
                   // return;
                    //当customErrors=Off时
                    //当customErrors = RemoteOnly,且在本地调试时
                    filterContext.Result = new ViewResult() { ViewName = "/Views/Shared/ErrorDetails.cshtml", ViewData = new ViewDataDictionary<HandleErrorInfo>(info) };
                    filterContext.ExceptionHandled = true;
                    filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
                }
            }

        }
    }

 


 

 

posted @ 2015-06-29 10:47  kavensu  阅读(1590)  评论(3编辑  收藏  举报