内容概览

本篇主要探讨一下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是一个各种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的功能强大之处。(文/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方法中,我们发现了一些线索:
    复制代码
    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的功能强大之处。(文/Creason

    相关文章:

    • 2022-12-23
    • 2021-11-19
    • 2021-08-10
    • 2022-12-23
    • 2022-12-23
    • 2022-12-23
    • 2021-12-31
    猜你喜欢
    • 2021-04-09
    • 2021-07-17
    • 2021-08-20
    • 2021-05-19
    • 2022-12-23
    相关资源
    相似解决方案