• MVC 过滤器1


    ASP.NET MVC 过滤器(一)

    前言

    前面的篇幅中,了解到了控制器的生成的过程以及在生成的过程中的各种注入点,按照常理来说篇幅应该到了讲解控制器内部的执行过程以及模型绑定、验证这些知识了。但是呢,在MVC框架中提供了一种机制在控制器方法执行之前我们还可以通过这种机制来做一些横向切面的操作,这种机制的实现就是过滤器了,在本篇和后续的篇幅中将会对几种过滤器做一番讲解,并且会对过滤器在框架中的一个执行过程进行粗略的讲解。

    ASP.NET MVC过滤器

    •   过滤器在系统框架中的整体对象模型
    •   IAuthorizationFilter授权认证过滤器的执行过程
    •   使用IAuthorizationFilter过滤器
    •   IActionFilter行为过滤器的执行过程
    •   自定义实现IActionFilter行为过滤器
    •   异常过滤器的使用

    过滤器在系统框架中的整体对象模型

    我们在获得控制器工厂生成的控制器后,执行某些控制器行为之前,总是要验证一些数据或者是请求信息什么的,这里就要用到过滤器的机制了,而在框架中过滤器是怎么运转的,通过本小节的学习会让你有个大概的了解。

    现在我们切入主题来讲解一下在MVC框架中的过滤器。

    图1

    如上图所示的这样,在控制器执行的时候会调用ControllerActionInvoker类型的InvokeAction()方法,而在InvokeAction()方法中,框架会默认的生成控制器描述对象ControllerDescriptor和控制器行为描述对象ActionDescriptor,这两种类型的对象都是对当前的控制器和所要请求的控制器方法信息的封装,这个知识点我们会在后续的篇幅中讲到,这里只须了解一下,忽略它们的生成过程。参照如下图:

    图2

     按照InvokeAction()方法的执行流程,到了生成FilterInfo类型的时候,我们都知道MVC框架给我们提供了四种过滤器,哪四种后面一一介绍,那么FilterInfo类型是干什么的呢?来看一下它的对象结构:

    复制代码
     1     //封装有关可用的操作筛选器的信息。
     2     public class FilterInfo
     3     {
     4         public FilterInfo();
     5         public FilterInfo(IEnumerable<Filter> filters);
     6         public IList<IActionFilter> ActionFilters { get; }
     7         public IList<IAuthorizationFilter> AuthorizationFilters { get; }
     8         public IList<IExceptionFilter> ExceptionFilters { get; }
     9         public IList<IResultFilter> ResultFilters { get; }
    10     }
    复制代码

    它的内部有着四种过滤器集合类型的属性,并且有个构造函数是接收IEnumerable<Filter>类型的,当FilterInfo类型在初始化的时候会根据构造函数传入的类型进行解析,并且对四个属性分别赋值,这就要涉及到另一个元数据描述对象Filter了。

    我们来看一下Filter对象的结构:

    复制代码
     1 //     表示一个元数据类,它包含对一个或多个筛选器接口的实现、筛选器顺序和筛选器范围的引用。
     2     public class Filter
     3     {
     4         public const int DefaultOrder = -1;
     5         public Filter(object instance, FilterScope scope, int? order);
     6 
     7         public object Instance { get; protected set; }
     8         public int Order { get; protected set; }
     9         public FilterScope Scope { get; protected set; }
    10     }
    复制代码

    看到这里有可能有的朋友不明白这个对象,具体怎么表示?因为元数据编程模式很少见,这里我给大家举个例子,一看就明白了:

    1     [Authorize(Order=1)]
    2     public class DemoController : Controller
    3     {
    4         ……
    5     }

    上面的这个列子则会在系统生成的时候生成一个Filter类型的对象,并且赋值Order等于1,而Filter类型中的Instance属性则是对上述例子中的Authorize类型实例引用,这就是元数据描述对象,当然了讲的不是太详细,能让大家明白就行了,Authorize类型的具体使用在下一篇中会有讲到。

    现在我们回归主题,如图2中所表示的那样,IEnumerable<Filter>集合类型是关键,那么怎么生成IEnumerable<Filter>集合类型?

    先是调用ControllerActionInvoker类型中的GetFilters()方法,我们看到方法的参数类型为控制器参数上下文对象和控制器行为元数据描述对象,这两个对象就够了,它们中包含的信息已经很多了,在ControllerActionInvoker的GetFilters()方法内部调用FilterProviderCollection类型的GetFilters(),和上面所述的类型方法签名一样,只不过返回类型有差异而已,而真正的根据参数执行生成Filter类型的对象是实现了IFilterProvider类型的对象,

    看一下IFilterProvider类型的结构:

    1 //     提供用于查找筛选器的接口。
    2     public interface IFilterProvider
    3     {
    4         IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor);
    5     }

    而这个对象是可以从外部注入进来的,在控制器(三)中提到过的,通过实现IDependencyResolver类型,而在框架中也会默认的实现一个(只是我通过反编译工具没看到,显示的是错误信息,表示很郁闷,后文中就叫它为默认实现)。在FilterProviderCollection类型的GetFilters()中,会通过默认实现来得到当前请求的行为上的所有过滤器元数据描述对象,并且进行排序、验证,这里就不多叙述了。然后返回IEnumerable<Filter>集合类型并且生成FilterInfo类型的对象。

    IAuthorizationFilter授权认证过滤器的执行过程

    图3

    先来看一下IAuthorizationFilter类型的定义:

    复制代码
     1     public interface IAuthorizationFilter
     2     {
     3         // 摘要:
     4         //     在需要授权时调用。
     5         //
     6         // 参数:
     7         //   filterContext:
     8         //     筛选器上下文。
     9         void OnAuthorization(AuthorizationContext filterContext);
    10     }
    复制代码

    看到如上的定义,再看图3IAuthorizationFilter类型的执行过程一目了然,根据ControllerContext控制器参数上下文对象和控制器行为据描述对象actionDescriptor生成AuthorizationContext授权认证过滤器参数上下文对象,并且会遍历FilterInfo类型中的AuthorizationFilters属性,挨个的去执行我们定义的过滤器。

    本篇的内容就讲到这里,下个篇幅中会讲到IAuthorizationFilter类型的使用

  • 相关阅读:
    【官网翻译】性能篇(四)为电池寿命做优化——使用Battery Historian分析电源使用情况
    【官网翻译】性能篇(三)为电池寿命做优化——概述
    【官网翻译】性能篇(二)通过线程提高性能
    Mybatis+Struts2的结合:实现用户插入和查找
    在安装mysql出现的错误以及解决方法
    关于PHP的内置服务器的使用
    误用.Net Redis客户端CSRedisCore,自己挖坑自己填
    dotnet代码管理之密钥分离策略
    dotnetcore三大Redis客户端对比和使用心得
    生产环境(基于docker)故障排除? 有感于博客园三番五次翻车
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3791213.html
Copyright © 2020-2023  润新知