内容概览
本篇主要探讨一下mvc一个重要的功能——Filter,我们通过研究源代码来了解Filter的原理,以及AOP 模式和各种Filter的执行。最重要的是大家通过理解Filter的代码,明白Filter的机制,从而对Filter有一个灵活的运用。
* 强大的Filter
* 为什么要Filter
* 获取“贴”在Action上的各种Filter
* Filter 的执行
强大的Filter
在使用asp.net mvc编程中,我想没有人不使用Filter,各种各样的Filter让我们的代码更加简练,功能更加丰富。比如你在Action上使用的每一个 [Attribute]大都是Filter。mvc提供四种类型的 Filter:IActionFilter,IAuthorizationFilter,IExceptionFilter,IResultFilter,这四种Filter足以我们所要实现的功能了,还提供了几个现成的可以使用的Filter:OutputCacheAttribute、 HandleErrorAttribute、AuthorizeAttribute。我们知道Filter是横切在Action上的,所以每次执行一个 Action,就会牵扯到这个Action的执行,不同类型的Filter提供不同类型的操作,Filter的设计就是一种AOP设计模式,所以这种方式十分灵活。
对于四种类型的Filter,各自有不同的方法,并以此来实现不同的功能,我们可以发挥自己的创造力,定制一个自己的Filter,来完成自己想要的功能。一般的Filter应用的场景有:缓存、验证、异常,以及处理Action上下文等,要想实现自己的Filter 只要继承相应的接口并重写接口的方法就可以了。
为什么要Filter
我们知道Filter是一种AOP模式,也就是说它提供我们可以对一系列操作进行横切干扰的手段,而且它解耦了依赖关系。想想这么一种场景,在传统的WebForm中,某一个页面的访问必须去验证当前用户是否符合某一个要求,比如已登录,这时,我们需要获取请求的上下文,分析当前用户的行为状态,从而得到这个条件是否成立,如果我们有很多这种页面,比如所有的后台管理页面需要管理员的登录,我们是不是每一页都写一个这样的验证呢?我们当然不会这么蠢,我们会聪明的把验证的逻辑封装成一个验证类,然后从各个页面调用验证类的验证逻辑,从而得知当前用户是否通过验证。
这样还是不够好,因为我们不得不在每一处反复写我们的调用验证类的验证代码,显然这些工作是重复的,因为那个时候还没有AOP的概念,所以我们不得不多付出点代价。
现在有了mvc,它理所应当为我们提供一个AOP的框架,而Filter就是这么一种模式,它的出现容许我们以一种更为简单的方式来实现类似的功能,在使用的时候我们只需要像该某个商品贴标签式的方式给Action“贴”上一个Attribute就行了,一切搞定,没有一点多于的代码。
获取“贴”在Action上的各种Filter
还是老套路,我们先寻找第一次出现Filter的地方。在ControllerActionInvoker类的 InvokeAction方法中,我们发现了一些线索:
- FilterInfo filterInfo = GetFilters(controllerContext, actionDescriptor);
FilterInfo是一个各种Filter是集合类,它有4个private字段和4个public属性:
- public IList<IActionFilter> ActionFilters
- public IList<IAuthorizationFilter> AuthorizationFilters
- public IList<IExceptionFilter> ExceptionFilters
- public IList<IResultFilter> ResultFilters
FilterInfo是一个没有“技术含量”的类,它的作用就是存放各种类型的Filter,下面看一下GetFilter方法,它有2个参数,一个是 ControllerContext对象,一个是ActionDescriptor对象,这两个对象在上一篇《Action的创建》中详细讨论过了。Go to Defination到GetFilter方法中,我们发现这个方法就是简单的调用了一下ActionDescriptor的GetFilters方法,我们知道AcionDesciptor对象的默认实现是ReflectedActionDescriptor对象,我们找到这个类的GetFilters 方法,下面是它的代码:
- public override FilterInfo GetFilters() {
- // Enumerable.OrderBy() is a stable sort, so this method preserves scope ordering.
- ●FilterAttribute[] typeFilters = (FilterAttribute[])MethodInfo.ReflectedType.
- GetCustomAttributes(typeof(FilterAttribute), true /* inherit */);
- ●FilterAttribute[] methodFilters = (FilterAttribute[])MethodInfo.GetCustomAttributes(
- typeof(FilterAttribute), true /* inherit */);
- ●List<FilterAttribute> orderedFilters = typeFilters.Concat(methodFilters).OrderBy(
- attr => attr.Order).ToList();
- ●FilterInfo filterInfo = new FilterInfo();
- MergeFiltersIntoList(orderedFilters, filterInfo.ActionFilters);
- MergeFiltersIntoList(orderedFilters, filterInfo.AuthorizationFilters);
- MergeFiltersIntoList(orderedFilters, filterInfo.ExceptionFilters);
- MergeFiltersIntoList(orderedFilters, filterInfo.ResultFilters);
- return filterInfo;
- }
上面的代码中带有黑点标记的是根据反射得到的Attribute,然后根据它们的Order进行排序。得到一个有序的Filter的集合后,下一步就是对不同类型的Filter进行分类,首先实例化一个FilterInfo对象,然后调用静态方法 MergeFilterIntoList,这个方法也很简单:
- private static void MergeFiltersIntoList<TFilter>(
- IList<FilterAttribute> allFilters,
- IList<TFilter> destFilters)
- where TFilter : class {
- foreach (FilterAttribute filter in allFilters) {
- TFilter castFilter = filter as TFilter;
- if (castFilter != null) {
- destFilters.Add(castFilter);
- }
- }
- }
该方法有两个参数,一个是所有的Filter,一个是分类后的Filter,由于不同类型的Filter继承了不同的接口,所以不同类型的Filter经过as运算符后,类型相同的装换成功,对象不为null,类型不同的转换后为null,从而对各种不同类型的 Filter进行分类。
到目前为止,所有的Filter已经获取完毕,但是我们忘了一点,就是Controller本身也是一个 Filter。看一下Controller类是签名就知道了:
- public abstract class Controller : ControllerBase,
- IActionFilter, IAuthorizationFilter, IDisposable, IExceptionFilter, IResultFilter
在Controller类中有这些接口的virtual方法,我们可能在一个Controller中 override这些方法,那这些Filter是怎么获取的呢?答案在ControllerActionInvoker类的GetFilters方法中:
- protected virtual FilterInfo GetFilters(ControllerContext controllerContext,
- ActionDescriptor actionDescriptor) {
- FilterInfo filters = actionDescriptor.GetFilters();
- // if the current controller implements one of the filter interfaces,
- // it should be added to the list at position 0
- ●ControllerBase controller = controllerContext.Controller;
- ●AddControllerToFilterList(controller, filters.ActionFilters);
- ●AddControllerToFilterList(controller, filters.ResultFilters);
- ●AddControllerToFilterList(controller, filters.AuthorizationFilters);
- ●AddControllerToFilterList(controller, filters.ExceptionFilters);
- return filters;
- }
从上面代码的注释就可以理解这一点。AddControllerToFilterList方法就是把 Controller放入到Filter的行列中。下面为该方法的实现:
- private static void AddControllerToFilterList<TFilter>(ControllerBase controller, IList<TFilter> filterList)
- where TFilter : class {
- TFilter controllerAsFilter = controller as TFilter;
- if (controllerAsFilter != null) {
- filterList.Insert(0, controllerAsFilter);
- }
- }
同样,它也先判断该Controller是否实现了某个类型Filter的接口,如果实现该类型Filter的接口就说明它是一个Filter,于是把它加入到相应类型的Filter列表中。到这里所有的Filter才真正全被收集起来。
Filter的执行
我们获取Filter是为了执行某些操作,所以下一步就是执行Filter的方法。由于执行各种类型的Filter 的过程比较复杂,涉及到的类也非常多,我打算把这节内容放到下一篇文章中介绍。同时在Filter执行也是一个承上启下的过程,我会在下一篇文章中详细的讲述。
总结
在本篇文章中,讲述的内容非常有限,主要讨论了怎么获取Filter的,以及Controller与各种 Filter的关系,还有Filter的4种类型,但是我们没有具体讨论4种类型Filter的方法。还有最终要的就是大家通过这个探究这个过程,真正了理解Filter的设计思想和AOP在mvc中的运用,以及Filter的功能强大之处。