本文 ASP.NET MVC中使用拦截器摘要: ASP.NET MVC框架内置了拦截Action的机制。确切的分为:Action拦截器、Result拦截器和Exception拦截器三种。所谓 ASP.NET MVC拦截器,就是一个普通的类,该类需要继承FilterAttribute基类,Action拦截器还要实现IActionFilter接口,而Exception拦截器需要实现IExceptionFilter接口。
Action执行过滤的接口为:IActionFilter,它有两个方法,OnActionExecuted:作用是Action执行后过滤;OnActionExecuting:Action执行前过滤。而FilterAttribute则表示用在属性上的成员筛选器。
一、日志拦截器
这个类继承了FilterAttribute并实现了接口的IActionFilter的两个方法:OnActionExecuting在被拦截Action前执行了准备写入日志操作,OnActionExecuted在被拦截Action后执行操作完成日志。两个方法都有一个参数,虽然类型不同,但其实都是一个作用:被拦截Action的上下文。
二、异常拦截器
异常拦截器一样需要继承FilterAttribute,但是不要实现IActionFilter,而是要实现IExceptionFilter接口,这个接口只有一个方法:OnException,顾名思义,当然是发生异常时被调用了。我们看看我让它做了什么:首先将异常信息(ExceptionContext一样也是上下文,而其成员的Exception就是一个Exception类型的实例,就是被抛出的异常)记录到ViewData相应的键值里,然后我们要呈现Error这个视图。
注意!这里已经不是Controller里了,而是另一个类,所以当然不能调用View方法返回ViewResult实例了。我们只好新建一个ViewResult实例,并将其视图名设为Error,将上下文中的DataView传过去。
最后那行filterContext.ExcepitonHandled = true;很重要,这行的意思是告诉系统,异常已经处理,不要再次处理了。
使用拦截器固然很爽,但是要注意两个地方:
1.Action拦截器的作用范围
除了用Action拦截器标记一个Action方法外,你也可以用来标记一个完成的控制器类。如果这样的话,这个Action拦截器将会应用到该控制器的所有Action方法上。
另外,如果你的控制器类继承自别的控制器类,而基控制器类可能有它自己的Action拦截器Attributes。如果你在子类中重写了基控制器类的Action方法,则子类的该Action方法也会有它自己的从基类继承而来的Action拦截器Attributes。
2.Action拦截器的执行顺序
每一个Action拦截器都有一个 Order 属性,用来决定Action拦截器在该范围内的执行顺序。Order属性必需是0(默认值)或者更大的整数值。省略Order属性则会给该拦截器的Order值为 -1, 表明为指明顺序。任何一个在同一范围的Action拦截器Order设为 -1 的都将按不确定的顺序执行,单在此之前拦截器有一个特定的顺序(注:下面会说到).
当设置Order属性的值的时候,必需指定一个唯一的值。如果两个或者更多的Action拦截器具有相同的Order属性值,将会抛出一个异常。
来看一个示例:
[Filter1(Order = 2)]
[Filter2(Order = 3)]
[Filter3(Order = 1)]
public void Index()
{
RenderView("Index");
}
[Filter2(Order = 3)]
[Filter3(Order = 1)]
public void Index()
{
RenderView("Index");
}
Filter的执行顺序为:Filter3 => Filter1 => Filter2.
综上所述,使用拦截器显而易见的优点:
1. 解决了部分代码重复的问题。很多日志处理代码和异常处理代码是很相似的,这样就导致了各个Action中存在大量重复代码。
2. 职责的明确化。 Controller仅仅是控制器,只负责表示逻辑,而不应该被一大堆日志处理代码和try...catch块包围。我们要的Action,应该是干净的、工整的、仅包含表示逻辑的Action。
3. 代码更加优雅。
当然了,也有他的缺点,在 ASP.NET MVCController中一个Action最好不要超过2,3个帽子(拦截器或过滤器),否则性能会受到影响。
关于更多的业务组件的内容,大家可以访问http://www.po-soft.com/