1)自动在Views/Shared 文件夹下面自动添加一个Error.cshtml 文件,这个文件就是我们自定义错误页面经常使用的
2)会在App_Start/FilterConfig.cs 中添加一个关于错误处理的Global Filter.
filters.Add(newHandleErrorAttribute());
要开启自定义错误页面,我们自己需要做的就是:
1)修改 Error.cshtml , 让其按我们的方式/样式展现错误信息
2)修改 Web.config,开启 custom error
<customErrorsmode="On"/>
那,mvc 是怎么帮我们处理的的呢, 他们如何转向Error.cshtml 视图的,又是怎么给Model赋值的?
一开时,我以为 mvc 有一个内置的ErrorController --- 因为这符合 从Controller - > view的一般思维--- 来控制的, 事实上不是的!这一切都使由 HandleErrorAttribute 来控制的。
我们来看一看HandleErrorAttribute 的定义:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public class HandleErrorAttribute : FilterAttribute, IExceptionFilter
可以看到, 它既是一个 Attribute 也是一个 Filter。也就是说我们既可以针对具体的Controller或者Action来设置,
[HandleError]
public class TaskStatusController : GridControllerBase
{
[HandleError]
public ActionResult Index()
{
也可以在注册在 GlobalFilterCollection里(默认生成这样的), 作为一个全局的
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
}
当然,这些还不足以说明 custom error 是怎么工作的, 我们通过反射看一下HandleErrorAttribute这个类, 就会很明晰了:
....
private const string DefaultView = "Error";
...
/// <summary>
/// Called when an exception occurs.
/// </summary>
/// <param name="filterContext">The action-filter context.</param><exception cref="T:System.ArgumentNullException">The <paramref name="filterContext"/> parameter is null.</exception>
public virtual void OnException(ExceptionContext filterContext)
{
if (filterContext == null)
throw new ArgumentNullException("filterContext");
if (filterContext.IsChildAction || filterContext.ExceptionHandled || !filterContext.HttpContext.IsCustomErrorEnabled)
return;
Exception exception = filterContext.Exception;
if (new HttpException((string) null, exception).GetHttpCode() != 500 || !this.ExceptionType.IsInstanceOfType((object) exception))
return;
string controllerName = (string) filterContext.RouteData.Values["controller"];
string actionName = (string) filterContext.RouteData.Values["action"];
HandleErrorInfo model = new HandleErrorInfo(filterContext.Exception, controllerName, actionName);
ExceptionContext exceptionContext = filterContext;
ViewResult viewResult1 = new ViewResult();
viewResult1.ViewName = this.View;
viewResult1.MasterName = this.Master;
viewResult1.ViewData = (ViewDataDictionary) new ViewDataDictionary<HandleErrorInfo>(model);
viewResult1.TempData = filterContext.Controller.TempData;
ViewResult viewResult2 = viewResult1;
exceptionContext.Result = (ActionResult) viewResult2;
filterContext.ExceptionHandled = true;
filterContext.HttpContext.Response.Clear();
filterContext.HttpContext.Response.StatusCode = 500;
filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
}
注意 02 行, 默认的错误处理页面就是Error 这个 view
同时注意21,22, 这里代码我没有贴全,反正就是直接呈现Error 这个视图了, 没有经过任何 Controller!