zoukankan      html  css  js  c++  java
  • 如何使用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的功能强大之处。

  • 相关阅读:
    PAT顶级 1024 Currency Exchange Centers (35分)(最小生成树)
    Codeforces 1282B2 K for the Price of One (Hard Version)
    1023 Have Fun with Numbers (20)
    1005 Spell It Right (20)
    1092 To Buy or Not to Buy (20)
    1118 Birds in Forest (25)
    1130 Infix Expression (25)
    1085 Perfect Sequence (25)
    1109 Group Photo (25)
    1073 Scientific Notation (20)
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/2873483.html
Copyright © 2011-2022 走看看