一、异常过滤器
异常筛选器用于实现IExceptionFilter接口,并在ASP.NET MVC管道执行期间引发了未处理的异常时执行。异常筛选器可用于执行诸如日志记录或显示错误页之类的任务。HandleErrorAttribute类是异常筛选器的一个示例。
先来看看HandleErrorAttribute类的定义:
#region 程序集 System.Web.Mvc, Version=5.2.7.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35 // D:\Practice\MVC\自定义异常过滤器\MVCCuetomerExcepFilter\packages\Microsoft.AspNet.Mvc.5.2.7\lib\net45\System.Web.Mvc.dll #endregion namespace System.Web.Mvc { // // 摘要: // 表示一个特性,该特性用于处理由操作方法引发的异常。 [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)] public class HandleErrorAttribute : FilterAttribute, IExceptionFilter { // // 摘要: // 初始化 System.Web.Mvc.HandleErrorAttribute 类的新实例。 public HandleErrorAttribute(); // // 摘要: // 获取或设置异常的类型。 // // 返回结果: // 异常的类型。 public Type ExceptionType { get; set; } // // 摘要: // 获取或设置用于显示异常信息的母版视图。 // // 返回结果: // 母版视图。 public string Master { get; set; } // // 摘要: // 获取此特性的唯一标识符。 // // 返回结果: // 此特性的唯一标识符。 public override object TypeId { get; } // // 摘要: // 获取或设置用于显示异常信息的页视图。 // // 返回结果: // 页视图。 public string View { get; set; } // // 摘要: // 在发生异常时调用。 // // 参数: // filterContext: // 操作筛选器上下文。 // // 异常: // T:System.ArgumentNullException: // filterContext 参数为 null。 public virtual void OnException(ExceptionContext filterContext); } }
从代码中可以看出HandleErrorAttribute继承了IExceptionFilter接口,并且有一个虚方法,如果要自定义异常过滤器,只需要继承HandleErrorAttribute类并重写HandleErrorAttribute类里面的虚方法即可。
二、示例
1、创建异常类
新建一个ExceptionFilters类继承自HandleErrorAttribute,并重写OnException方法,代码如下:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; namespace MVCCuetomerExcepFilter.Extension { /// <summary> /// 异常过滤器 /// </summary> public class ExceptionFilters : HandleErrorAttribute { /// <summary> /// 在异常发生时调用 /// </summary> /// <param name="filterContext"></param> public override void OnException(ExceptionContext filterContext) { // 判断是否已经处理过异常 if(!filterContext.ExceptionHandled) { // 获取出现异常的controller和action名称,用于记录 string strControllerName = filterContext.RouteData.Values["controller"].ToString(); string strActionName = filterContext.RouteData.Values["action"].ToString(); // 定义一个HandleErrorInfo,用于Error视图展示异常信息 HandleErrorInfo info = new HandleErrorInfo(filterContext.Exception, strControllerName, strActionName); ViewResult result = new ViewResult { ViewName = this.View, // 定义ViewData,泛型 ViewData = new ViewDataDictionary<HandleErrorInfo>(info) }; // 设置操作结果 filterContext.Result = result; // 设置已经处理过异常 filterContext.ExceptionHandled = true; } //base.OnException(filterContext); } } }
2、创建控制器
新建一个控制器,代码如下:
using MVCCuetomerExcepFilter.Extension; using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; namespace MVCCuetomerExcepFilter.Controllers { public class ExceptionController : Controller { // GET: Exception /// <summary> /// View表示发生异常时指定的视图 /// 这里表示发生异常时使用ExceptionDetails视图 /// </summary> /// <returns></returns> [ExceptionFilters(View =("ExceptionDetails"))] public ActionResult Index() { // 测试抛出异常 throw new NullReferenceException("测试抛出的异常"); } } }
异常发生时使用ExceptionDetails视图,所以在Shared文件夹里面新建ExceptionDetails视图,代码如下:
<!--使用强类型视图--> @model System.Web.Mvc.HandleErrorInfo @{ Layout = null; } <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>异常</title> </head> <body> <p> 抛错控制器:<b>@Model.ControllerName</b> 抛错方法:<b>@Model.ActionName</b> 抛错类型:<b> @Model.Exception.GetType().Name </b> </p> <p> 异常信息:<b>@Model.Exception.Message</b> </p> <p> 堆栈信息: </p> <pre>@Model.Exception.StackTrace</pre> </body> </html>
三、测试
运行程序,访问Exception控制器的Index方法,效果如下:
四、总结
上面的案例演示了一个自定义异常类,很明显比HandleError要灵活,在自定义异常类里面可以写很多与业务相关的代码。
GitHub代码地址:git@github.com:JiangXiaoLiang1988/CustomerHandleErrorFilter.git