如何使用ASP.NET MVC的Filter

内容概览

本篇主要探讨一下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方法中,我们发现了一些线索:
  1. FilterInfo filterInfo = GetFilters(controllerContext, actionDescriptor);
复制代码
FilterInfo是一个各种Filter是集合类,它有4个private字段和4个public属性:
  1. public IList<IActionFilter> ActionFilters
  2. public IList<IAuthorizationFilter> AuthorizationFilters 
  3. public IList<IExceptionFilter> ExceptionFilters
  4. public IList<IResultFilter> ResultFilters
复制代码
FilterInfo是一个没有“技术含量”的类,它的作用就是存放各种类型的Filter,下面看一下GetFilter方法,它有2个参数,一个是 ControllerContext对象,一个是ActionDescriptor对象,这两个对象在上一篇《Action的创建》中详细讨论过了。Go to Defination到GetFilter方法中,我们发现这个方法就是简单的调用了一下ActionDescriptor的GetFilters方法,我们知道AcionDesciptor对象的默认实现是ReflectedActionDescriptor对象,我们找到这个类的GetFilters 方法,下面是它的代码:
  1. public override FilterInfo GetFilters() {
  2.     // Enumerable.OrderBy() is a stable sort, so this method preserves scope ordering.
  3.     ●FilterAttribute[] typeFilters = (FilterAttribute[])MethodInfo.ReflectedType.
  4.                 GetCustomAttributes(typeof(FilterAttribute), true /* inherit */);
  5.     ●FilterAttribute[] methodFilters = (FilterAttribute[])MethodInfo.GetCustomAttributes(
  6.                 typeof(FilterAttribute), true /* inherit */);
  7.     ●List<FilterAttribute> orderedFilters = typeFilters.Concat(methodFilters).OrderBy(
  8.                 attr => attr.Order).ToList();

  9.     ●FilterInfo filterInfo = new FilterInfo();
  10.     MergeFiltersIntoList(orderedFilters, filterInfo.ActionFilters);
  11.     MergeFiltersIntoList(orderedFilters, filterInfo.AuthorizationFilters);
  12.     MergeFiltersIntoList(orderedFilters, filterInfo.ExceptionFilters);
  13.     MergeFiltersIntoList(orderedFilters, filterInfo.ResultFilters);
  14.     return filterInfo;
  15. }
复制代码
上面的代码中带有黑点标记的是根据反射得到的Attribute,然后根据它们的Order进行排序。得到一个有序的Filter的集合后,下一步就是对不同类型的Filter进行分类,首先实例化一个FilterInfo对象,然后调用静态方法 MergeFilterIntoList,这个方法也很简单:
  1. private static void MergeFiltersIntoList<TFilter>(
  2.     IList<FilterAttribute> allFilters, 
  3.     IList<TFilter> destFilters) 
  4.     where TFilter : class {
  5.     foreach (FilterAttribute filter in allFilters) {
  6.         TFilter castFilter = filter as TFilter;
  7.         if (castFilter != null) {
  8.             destFilters.Add(castFilter);
  9.         }
  10.     }
  11. }
复制代码
该方法有两个参数,一个是所有的Filter,一个是分类后的Filter,由于不同类型的Filter继承了不同的接口,所以不同类型的Filter经过as运算符后,类型相同的装换成功,对象不为null,类型不同的转换后为null,从而对各种不同类型的 Filter进行分类。

到目前为止,所有的Filter已经获取完毕,但是我们忘了一点,就是Controller本身也是一个 Filter。看一下Controller类是签名就知道了:
  1. public abstract class Controller : ControllerBase, 
  2.     IActionFilter, IAuthorizationFilter, IDisposable, IExceptionFilter, IResultFilter
复制代码
在Controller类中有这些接口的virtual方法,我们可能在一个Controller中 override这些方法,那这些Filter是怎么获取的呢?答案在ControllerActionInvoker类的GetFilters方法中:
  1. protected virtual FilterInfo GetFilters(ControllerContext controllerContext,
  2.             ActionDescriptor actionDescriptor) {
  3.     FilterInfo filters = actionDescriptor.GetFilters();

  4.     // if the current controller implements one of the filter interfaces,
  5.     // it should be added to the list at position 0
  6.     ●ControllerBase controller = controllerContext.Controller;
  7.     ●AddControllerToFilterList(controller, filters.ActionFilters);
  8.     ●AddControllerToFilterList(controller, filters.ResultFilters);
  9.     ●AddControllerToFilterList(controller, filters.AuthorizationFilters);
  10.     ●AddControllerToFilterList(controller, filters.ExceptionFilters);

  11.     return filters;
  12. }
复制代码
从上面代码的注释就可以理解这一点。AddControllerToFilterList方法就是把 Controller放入到Filter的行列中。下面为该方法的实现:
  1. private static void AddControllerToFilterList<TFilter>(ControllerBase controller, IList<TFilter> filterList) 
  2.             where TFilter : class {
  3.     TFilter controllerAsFilter = controller as TFilter;
  4.     if (controllerAsFilter != null) {
  5.         filterList.Insert(0, controllerAsFilter);
  6.     }
  7. }
复制代码
同样,它也先判断该Controller是否实现了某个类型Filter的接口,如果实现该类型Filter的接口就说明它是一个Filter,于是把它加入到相应类型的Filter列表中。到这里所有的Filter才真正全被收集起来。

Filter的执行

我们获取Filter是为了执行某些操作,所以下一步就是执行Filter的方法。由于执行各种类型的Filter 的过程比较复杂,涉及到的类也非常多,我打算把这节内容放到下一篇文章中介绍。同时在Filter执行也是一个承上启下的过程,我会在下一篇文章中详细的讲述。

总结

在本篇文章中,讲述的内容非常有限,主要讨论了怎么获取Filter的,以及Controller与各种 Filter的关系,还有Filter的4种类型,但是我们没有具体讨论4种类型Filter的方法。还有最终要的就是大家通过这个探究这个过程,真正了理解Filter的设计思想和AOP在mvc中的运用,以及Filter的功能强大之处。(文/Creason
内容概览

本篇主要探讨一下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方法中,我们发现了一些线索:
  1. FilterInfo filterInfo = GetFilters(controllerContext, actionDescriptor);
复制代码
FilterInfo是一个各种Filter是集合类,它有4个private字段和4个public属性:
  1. public IList<IActionFilter> ActionFilters
  2. public IList<IAuthorizationFilter> AuthorizationFilters 
  3. public IList<IExceptionFilter> ExceptionFilters
  4. public IList<IResultFilter> ResultFilters
复制代码
FilterInfo是一个没有“技术含量”的类,它的作用就是存放各种类型的Filter,下面看一下GetFilter方法,它有2个参数,一个是 ControllerContext对象,一个是ActionDescriptor对象,这两个对象在上一篇《Action的创建》中详细讨论过了。Go to Defination到GetFilter方法中,我们发现这个方法就是简单的调用了一下ActionDescriptor的GetFilters方法,我们知道AcionDesciptor对象的默认实现是ReflectedActionDescriptor对象,我们找到这个类的GetFilters 方法,下面是它的代码:
  1. public override FilterInfo GetFilters() {
  2.     // Enumerable.OrderBy() is a stable sort, so this method preserves scope ordering.
  3.     ●FilterAttribute[] typeFilters = (FilterAttribute[])MethodInfo.ReflectedType.
  4.                 GetCustomAttributes(typeof(FilterAttribute), true /* inherit */);
  5.     ●FilterAttribute[] methodFilters = (FilterAttribute[])MethodInfo.GetCustomAttributes(
  6.                 typeof(FilterAttribute), true /* inherit */);
  7.     ●List<FilterAttribute> orderedFilters = typeFilters.Concat(methodFilters).OrderBy(
  8.                 attr => attr.Order).ToList();

  9.     ●FilterInfo filterInfo = new FilterInfo();
  10.     MergeFiltersIntoList(orderedFilters, filterInfo.ActionFilters);
  11.     MergeFiltersIntoList(orderedFilters, filterInfo.AuthorizationFilters);
  12.     MergeFiltersIntoList(orderedFilters, filterInfo.ExceptionFilters);
  13.     MergeFiltersIntoList(orderedFilters, filterInfo.ResultFilters);
  14.     return filterInfo;
  15. }
复制代码
上面的代码中带有黑点标记的是根据反射得到的Attribute,然后根据它们的Order进行排序。得到一个有序的Filter的集合后,下一步就是对不同类型的Filter进行分类,首先实例化一个FilterInfo对象,然后调用静态方法 MergeFilterIntoList,这个方法也很简单:
  1. private static void MergeFiltersIntoList<TFilter>(
  2.     IList<FilterAttribute> allFilters, 
  3.     IList<TFilter> destFilters) 
  4.     where TFilter : class {
  5.     foreach (FilterAttribute filter in allFilters) {
  6.         TFilter castFilter = filter as TFilter;
  7.         if (castFilter != null) {
  8.             destFilters.Add(castFilter);
  9.         }
  10.     }
  11. }
复制代码
该方法有两个参数,一个是所有的Filter,一个是分类后的Filter,由于不同类型的Filter继承了不同的接口,所以不同类型的Filter经过as运算符后,类型相同的装换成功,对象不为null,类型不同的转换后为null,从而对各种不同类型的 Filter进行分类。

到目前为止,所有的Filter已经获取完毕,但是我们忘了一点,就是Controller本身也是一个 Filter。看一下Controller类是签名就知道了:
  1. public abstract class Controller : ControllerBase, 
  2.     IActionFilter, IAuthorizationFilter, IDisposable, IExceptionFilter, IResultFilter
复制代码
在Controller类中有这些接口的virtual方法,我们可能在一个Controller中 override这些方法,那这些Filter是怎么获取的呢?答案在ControllerActionInvoker类的GetFilters方法中:
  1. protected virtual FilterInfo GetFilters(ControllerContext controllerContext,
  2.             ActionDescriptor actionDescriptor) {
  3.     FilterInfo filters = actionDescriptor.GetFilters();

  4.     // if the current controller implements one of the filter interfaces,
  5.     // it should be added to the list at position 0
  6.     ●ControllerBase controller = controllerContext.Controller;
  7.     ●AddControllerToFilterList(controller, filters.ActionFilters);
  8.     ●AddControllerToFilterList(controller, filters.ResultFilters);
  9.     ●AddControllerToFilterList(controller, filters.AuthorizationFilters);
  10.     ●AddControllerToFilterList(controller, filters.ExceptionFilters);

  11.     return filters;
  12. }
复制代码
从上面代码的注释就可以理解这一点。AddControllerToFilterList方法就是把 Controller放入到Filter的行列中。下面为该方法的实现:
  1. private static void AddControllerToFilterList<TFilter>(ControllerBase controller, IList<TFilter> filterList) 
  2.             where TFilter : class {
  3.     TFilter controllerAsFilter = controller as TFilter;
  4.     if (controllerAsFilter != null) {
  5.         filterList.Insert(0, controllerAsFilter);
  6.     }
  7. }
复制代码
同样,它也先判断该Controller是否实现了某个类型Filter的接口,如果实现该类型Filter的接口就说明它是一个Filter,于是把它加入到相应类型的Filter列表中。到这里所有的Filter才真正全被收集起来。

Filter的执行

我们获取Filter是为了执行某些操作,所以下一步就是执行Filter的方法。由于执行各种类型的Filter 的过程比较复杂,涉及到的类也非常多,我打算把这节内容放到下一篇文章中介绍。同时在Filter执行也是一个承上启下的过程,我会在下一篇文章中详细的讲述。

总结

在本篇文章中,讲述的内容非常有限,主要讨论了怎么获取Filter的,以及Controller与各种 Filter的关系,还有Filter的4种类型,但是我们没有具体讨论4种类型Filter的方法。还有最终要的就是大家通过这个探究这个过程,真正了理解Filter的设计思想和AOP在mvc中的运用,以及Filter的功能强大之处。(文/Creason
原文地址:https://www.cnblogs.com/stalwart/p/1764872.html