使用HandleErrorAttribute处理异常

ASP.NET MVC 默认提供了一个异常过滤器HandleError特性,使用该特性能够极为方便的捕捉并处理控制器和操做抛出的异常,也能够将此特性注册为全局异常过滤器从而捕捉项目中的全部异常。若是想要简单的消灭错误黄页(错误详细页),使用HandlerErrorAttribute是不错的选择!css

本文演示项目下载地址:GlobalExceptionHandle-By-HandleErrorAttribute.zip,项目使用的VS2013和ASP.NET MVC 5框架,项目中也拷贝了HandleErrorAttribute的源码以供参考。html

HandleErrorAttribute初步使用

使用HandleErrorAttribute处理异常很简单,首先要开启Web.config配置文件中的自定义错误,由于HandleError特性是依赖自定义错误的,customErrors的Mode必需要设置为On或RemoteOnly:web

<customErrors mode="On" defaultRedirect="~/Error/Index"></customErrors>

到了这里基本上就成功启用了异常过滤器,由于VS2013新建的ASP.NET MVC 5项目默认将HandleError注册为全局异常过滤器,只要项目中的控制器和操做方法有抛出异常,默认就会被HandleError特性捕获,从而跳转到默认的错误详细页面~/Views/Shared/Error.cshtml。打开项目下App_Start的FilterConfig类(全局过滤器配置类),能够看到已经被注册的HandleErrorAttribute类:服务器

FilterConfig类中全局注册了HandleErrorAttribute类

public class FilterConfig { public static void RegisterGlobalFilters(GlobalFilterCollection filters) { filters.Add(new HandleErrorAttribute()); //若是要更改默认的错误视图,须要设置View属性 //filters.Add(new HandleErrorAttribute() { View = "~/Views/Error/CustomHttpError.cshtml" }); } }

备注:关于FilterConfig类,若是不清楚的朋友能够看这篇文章:ASP.NET MVC 5 学习笔记之FilterConfig类网络

这里能够动态抛出一些异常来进行测试,在默认的Home控制器下复制以下代码:mvc

public class HomeController : Controller { public ActionResult Index() { return View(); } /// <summary> /// 抛出HTTP 500 /// </summary> /// <returns></returns> public ActionResult ThrowHttp500() { throw new HttpException(500, "服务器错误"); } /// <summary> /// 抛出HTTP 404 /// </summary> /// <returns></returns> public ActionResult ThrowHttp404() { throw new HttpException(404, "页面未找到"); } /// <summary> /// 抛出未引用对象异常 /// ,此处单独使用HandleError特性 /// ,并指定异常类型及响应视图 /// </summary> /// <returns></returns> [HandleError(ExceptionType = typeof(NullReferenceException),View="CustomError")] public ActionResult ThrowNullReferenceException() { throw new NullReferenceException(); } /// <summary> /// 引起输入字符串的格式不正确异常 /// ,此处指定了响应的错误页面 /// ,因为是不一样的控制器因此要完整的相对路径 /// </summary> /// <returns></returns> [HandleError(View = "~/Views/Error/CustomHttpError.cshtml")] public ActionResult ThrowFormatException() { string str = ""; int count = Convert.ToInt32(str); return View("Index"); } }

备注:记得添加对应的错误视图页和控制器,建议直接下载演示项目。框架

首页操做演示界面以下:ide

ASP.NET MVC 5 中HandleErrorAttribute类演示项目

灵活运用HandleError特性

HandleError特性提供了许多属性,咱们能够更加灵活的处理项目中抛出的异常。文档截图:post

HandleError的属性截图

通常来讲最经常使用的属性是View,Order和ExceptionType,至于AllowMultiple属性,除非业务有特殊要求,否则默认都是容许的。学习

自定义错误信息页面

先说View属性,设置此属性就能够自定义要跳转的错误视图页,不然一旦有异常抛出,默认会跳转到Error.cshtml这个页面,该页面路径为:~/Views/Shared/Error.cshtml。

设置View属性必定要注意路径问题,若是跳转的异常信息页面属于其余控制器,即控制器路由地址不一样,那么必定要用完整的相对路径,不然引起二次异常:未找到视图**或其母版视图,或没有视图引擎支持搜索的位置。,好比下面代码(此声明是在Home控制器中,可是要跳转的错误页面则是在Error控制器中):

[HandleError(View = "~/Views/Error/CustomHttpError.cshtml")]

若是跳转的异常页面是属于当前控制器,或者是属于公共视图页的,就能够直接设置视图名称,代码以下:

[HandleError(View="CustomError")]

备注:CustomError是一个公共的自定义错误信息视图页面,另外公共视图页都是放在~/Views/Shared/这个路径下。

若是不想使用默认的Error.cshtml,想将全部的异常响应跳转到自定义的异常信息视图页,那么只要经过全局过滤器配置类FilterConfig,在注册HandleErrorAttribute时设置View属性便可,代码以下:

public class FilterConfig { public static void RegisterGlobalFilters(GlobalFilterCollection filters) { filters.Add(new HandleErrorAttribute() { View = "~/Views/Error/CustomHttpError.cshtml" }); } }

一样要注意视图路径问题,其实这里最好使用公共视图页。这里额外说下Master属性,此属性能够指定要跳转的视图页的母板。基本上不多用,除非项目业务有须要,好比动态控制母板什么的,否则的话都是在视图中直接设置好的。

获取详细的异常信息

HandleErrorInfo类是HandleErrorAttribute默认提供的错误信息实体

HandleErrorInfo类属性截图

能够经过此类获取引起异常的控制器和操做方法名称,以及经过获取Exception对象获取详细的错误内容。只要在对应的视图页中声明此类便可,演示代码:

@model System.Web.Mvc.HandleErrorInfo
@{
    ViewBag.Title = "自定义的公共错误页面";
}
@section styles{
    <style type="text/css"> p {padding: 10px;} </style> } <h2>自定义的公共错误页面</h2> @if (Model != null) { <p class="bg-danger text-danger"> 异常类型:@Model.Exception.GetType().Name </p> <p class="bg-danger text-danger"> 触发异常的控制器:@Model.ControllerName </p> <p class="bg-danger text-danger"> 触发异常的操做方法:@Model.ActionName </p> <p class="bg-danger text-danger"> 错误信息:@Model.Exception.Message </p> <p class="bg-info text-info"> 页面路径:~/Views/Shared/CustomError.cshtml </p> }

演示的视图截图:

ASP.NET MVC 5演示项目截图

针对异常类型

ExceptionType属性可让HandleError针对某种异常类型作出处理,能够搭配View属性来使用,便于跳转到不一样的异常信息页面,演示代码:

[HandleError(ExceptionType = typeof(NullReferenceException),View="CustomError")]

上面代码一旦捕获到NullReferenceException异常,就会跳转到CustomError视图页。注意一点,ExceptionType须要使用typeof转化异常类型。

关于过滤器的执行顺序

若是声明了多个HandleError异常过滤器,就须要使用到Order属性设置运行顺序。Order属性默认值为-1,也是最高优先级,正常来讲整数值越大优先级越低,可是因为HandleError是继承于IExceptionFilter接口,因此优先级顺序是相反的,也就是说整数值越大,优先级也就越大,这里分享下官方文档的资料

在 ASP.NET MVC 版本 1 和 2 中,OnException(ExceptionContext) 筛选器以正向顺序运行。 在 ASP.NET MVC 版本 3 及更高版本中,此顺序已反转。 ASP.NET MVC 中的异常筛选器的行为相似于 .NET Framework 中的异常处理程序,后者由内而外展开。

这里有两点须要注意:

  1. 若是Order属性小于-1会抛出异常,因此只能设置大于等于-1的整数值。
  2. 若是没有设置Order属性,因为默认值都是-1(即最高优先级),会致使过滤器的执行顺序变成无序随机。

使用HandleErrorAttribute的一些注意事项

虽然HandleError特性使用起来很简单,可是依然有不少须要注意不少地方,下面会详细的分析特性的局限性和一些缺点。

依赖于ASP.NET的自定义错误模块

若是customErrors mode="Off",则HandleError则无效,不对任何异常进行处理。

源码:

// If custom errors are disabled, we need to let the normal ASP.NET exception handler // execute so that the user can see useful debugging information. if (filterContext.ExceptionHandled || !filterContext.HttpContext.IsCustomErrorEnabled) { return; }

从源码中能够看到,当HttpContext.IsCustomErrorEnabled属性为false时(即未启用自定义错误),就不进行任何处理,直接return中止流程。

只能处理500服务器错误

像HTPP 40四、40一、503等错误代码,都是不处理的。源码能够很直接看出,只要不是500错误就直接return返回:

// If this is not an HTTP 500 (for example, if somebody throws an HTTP 404 from an action method), // ignore it. if (new HttpException(null, exception).GetHttpCode() != 500) { return; }

所以除了500错误,其余错误只能经过自定义错误模块配置响应的页面:

<customErrors mode="On" defaultRedirect="~/Error/Index"> <error redirect="~/Error/NotFound" statusCode="404"/> <error redirect="~/Error/NotFound" statusCode="400"/> </customErrors>

只能跳转到视图

HandleError只提供了一个View属性,因此响应的异常信息页也只能是视图,其余的静态页面或者.aspx之类的都是没法进行跳转的,可使用自定义异常过滤器实现此功能。

跳转的原理是经过设置ExceptionContext.Result属性:

filterContext.Result = new ViewResult { ViewName = View, MasterName = Master, ViewData = new ViewDataDictionary<HandleErrorInfo>(model), TempData = filterContext.Controller.TempData };

不利于SEO搜索引擎优化

这里涉及到部分SEO的知识,简单来讲错误页面是使用302跳转,所以对搜索引擎抓取网站内容并不友好。若是是互联网行业的网站,考虑到SEO的问题仍是不要用HandleErrorAttribute处理异常,相似企业系统的网站却是十分适合使用。

至于应对的方法能够参考此文:ASP.NET MVC全局异常处理和捕获的思路

同时声明多个HandleError的效果

多个HandleError最终只有一个过滤器会执行,其余的过滤器会自动中止执行,至因而哪一个过滤器执行则是依靠Order属性进行优先级肯定,原理是使用ExceptionContext.ExceptionHandled属性进行判断,一旦该属性为true则表示当前抛出的异常已经被其余过滤器处理了,直接return中止余下的流程。

高级进阶之继承HandleErrorAttribute实现自定义功能

经过继承HandleErrorAttribute类建立新的异常处理特性,可使咱们扩展更多的自定义功能,好比记录错误日志、发送错误信息邮件等。继承后只要重写此类中的OnException方法便可实现功能,演示代码以下:

public class CustomHandleErrorAttribute : HandleErrorAttribute { public override void OnException(ExceptionContext filterContext) { /* 调用基类的OnException方法,实现基础的功能。 * 若是要彻底的自定义,就不须要调用基类的方法 */ base.OnException(filterContext); /* 此处可进行记录错误日志,发送错误通知等操做 * 经过Exception对象和HttpException对象可获取相关异常信息。 * Exception exception = filterContext.Exception; * HttpException httpException = new HttpException(null, exception); */ } }

调用基类的OnException方法依然要注意HandleErrorAttribute类的一些限制,除非不使用基类的方法。继承后的新特性使用方法和HandleError同样,依然能够全局注册和局部使用。

若是须要彻底自定义异常处理的功能,建议直接继承IExceptionFilter接口以实现功能,能够参考这篇文章:ASP.NET MVC实现IExceptionFilter接口编写自定义异常处理过滤器


参考资料分享

  1. HandleErrorAttribute源码
  2. HandleErrorAttribute类
  3. GlobalFilterCollection类
  4. Exception对象

做者:十有三

出处:http://shiyousan.com/post/635838881238204198

欢迎转载本文,本文版权归做者全部,转载请声明出处或保留此段声明。^_^请尊重他人劳动成果,共建美好的网络环境。

相关文章
相关标签/搜索