摘要
在asp.net mvc中除了使用try...catch/finally来处理异常外,它提供了一种通过在Controller或者Action上添加特性的方式来处理异常。
HandleErrorAttribute
首先看一下该特性的定义
using System;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: // 操作筛选器上下文。 // // 异常: // System.ArgumentNullException: // filterContext 参数为 null。 public virtual void OnException(ExceptionContext filterContext); }}
ExceptionType:属性,相当于try catch(Exception)中的catch捕获的异常类型,默认所有异常类型。
View:异常展示视图,这个视图需要在目录Views/Shared/下。例如:
Order:该属性是父类FilterAttribute的一个属性,用来获取或者设置执行操作筛选器的顺序,默认-1,-1最先执行。
一个例子
在Index中直接抛出一个异常,我们现在需要做的就是通过HandlerError特性捕获到这个异常,并且在视图MyError上显示详细信息。
步骤1:添加特性
public class UserController : Controller { // GET: User [HandleError(ExceptionType = typeof(Exception), View = "MyError")] public ActionResult Index() { throw new Exception("Sorry,threre is an error in your web server."); } }
步骤2:定义错误视图,并通过@Model获取异常对象并显示错误信息。
@{ Layout = null;} @Model.Exception.GetType().Name @Model.Exception.Message @Model.ControllerName @Model.ActionName @Model.Exception.StackTrace
步骤3:注册过滤器。
在App_Start目录添加类FilterConfig
public class FilterConfig { public static void RegisterGlobalFilters(GlobalFilterCollection filters) { filters.Add(new HandleErrorAttribute()); } }
在Global.asax中注册
public class MvcApplication : System.Web.HttpApplication { protected void Application_Start() { AreaRegistration.RegisterAllAreas(); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); GlobalConfiguration.Configure(WebApiConfig.Register); } }
步骤4:开启自定义错误配置
...
测试
以上是采用ErrorHanlder的默认实现的方式,当然我们也可以自定义异常处理过滤器,方法很简单继承HandleErrorAttribute类,并且重写OnException方法即可。
////// 自定义异常过滤器 /// public class CustomerErrorAttribute : HandleErrorAttribute { public override void OnException(ExceptionContext filterContext) { //如果没有处理该异常 if (!filterContext.ExceptionHandled) { if (filterContext.Exception.Message.Contains("Sorry,threre is an error in your web server.")) { filterContext.ExceptionHandled = true; filterContext.HttpContext.Response.Write("这是一个自定义异常处理过滤器"); } } } }
public class UserController : Controller { // GET: User [CustomerError(ExceptionType = typeof(Exception), View = "MyError")] public ActionResult Index() { throw new Exception("Sorry,threre is an error in your web server."); } }
public class FilterConfig { public static void RegisterGlobalFilters(GlobalFilterCollection filters) { filters.Add(new HandleErrorAttribute()); filters.Add(new CustomerErrorAttribute()); } }
测试
好了,自定义的异常处理过滤器已经起作用了。
需要注意在自定义处理异常过滤器的时候需要重写OnException方法,该方法有一个ExceptionContext类型的参数。
// 摘要: // 提供使用 System.Web.Mvc.HandleErrorAttribute 类的上下文。 public class ExceptionContext : ControllerContext { // 摘要: // 初始化 System.Web.Mvc.ExceptionContext 类的新实例。 public ExceptionContext(); // // 摘要: // 使用指定的控制器上下文针对指定的异常初始化 System.Web.Mvc.ExceptionContext 类的新实例。 // // 参数: // controllerContext: // 控制器上下文。 // // exception: // 异常。 // // 异常: // System.ArgumentNullException: // exception 参数为 null。 public ExceptionContext(ControllerContext controllerContext, Exception exception); // 摘要: // 获取或设置异常对象。 // // 返回结果: // 异常对象。 public virtual Exception Exception { get; set; } // // 摘要: // 获取或设置一个值,该值指示是否已处理异常。 // // 返回结果: // 如果已处理异常,则为 true;否则为 false。 public bool ExceptionHandled { get; set; } // // 摘要: // 获取或设置操作结果。 // // 返回结果: // 操作结果。 public ActionResult Result { get; set; } }
需要注意的是,在自定义的异常过滤器中,如果对异常已经处理了,需要将ExceptionHandled设置为true,这样其它的过滤器可以根据该值判断当前异常是否已经处理过了。
通过异常处理过滤器的特性,你可以更方便的来处理action或者Controller中的异常,比try--catch用起来更方便,用这种方式,也可以简化异常处理的代码,少一些大块儿大块儿的异常处理代码。