ASP.NET core 的 Filter 是系统中经常用到的, 本文详细分享一下各种 Filter 定义, 执行的内部机制以及执行顺序.
一, 概述
ASP.NET Core MVC 中有好几种常用的筛选器, 例如 Authorization filters ,Resource filters,Action filters ,Exception filters ,Result filters, 他们运行在请求处理管道中的特定阶段, 例如 Authorization filters 当前请求的用户是否已授权. 如果请求未获授权, 则中止执行后面的请求处理. 其他几种 filters 也类似, 只是执行阶段不同. 如下图:
图一
Filter 从定义到执行, 本文通过四个阶段说明, 如下图:
图二
1. 定义: 以为例, 可以通过继承 ActionFilterAttribute 并 override 它的 OnActionExecuting 和 OnActionExecuted 方法实现.
2. 注册: 主要有三种方式: 在 Startup 的 AddMvc,Controller,Action 中注册.
3. 获取: 上一章有介绍, 在确定了处理请求的 Endpoint 后, 下一步就是创建创建 invoker, 它有个关键的属性就是 filters, 它由 FilterFactory 的 GetAllFilters 方法获取到.
4. 执行: invoker 的执行阶段, 会进入 InvokeFilterPipelineAsync, 在这里, 各种 Filter 按照图一的方式逐一被执行.
二, Filter 的定义
Filter 有好几种, 但由于本文主要是分享 Filter 的运行机制, 所以只以 ActionFilter 一种来举例, 现在定义一个 Test1Filter 如下:
- public class Test1Filter : ActionFilterAttribute
- {
- public override void OnActionExecuting(ActionExecutingContext context)
- {
- base.OnActionExecuting(context);
- //do.....
- }
- public override void OnActionExecuted(ActionExecutedContext context)
- {
- base.OnActionExecuted(context);
- //do......
- }
- }
很简单, 可以很方便的通过继承系统提供的 ActionFilterAttribute 并 override 它的相应方法即可.
三, Filter 的注册
Filter 定义好之后就是将其插入到处理管道中, 可以在 Startup 的 AddMvc,Controller,Action 中注册.
1. 全局: 在 Startup 的 AddMvc 中注册
- services.AddMvc(
- options => { options.Filters.Add(new Test6Filter()); options.Filters.Add(new Test4Filter()); }
- ).SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
2. 只对指定的 Controller 生效
- [Test5Filter]
- [Test3Filter]
- public class FlyLoloController : Controller
3. 只对指定的 Action 生效
- [Test2Filter]
- [Test1Filter]
- public JsonResult Index()
在实际业务中, 我们可以根据具体的需求来确定 Filter 的作用范围.
四, Filter 的获取
Filter 的获取是在 FilterFactory 的 GetAllFilters 方法中,
- public static FilterFactoryResult GetAllFilters(IFilterProvider[] filterProviders, ActionContext actionContext)
- {
- // 省略......
- var orderedFilters = actionDescriptor.FilterDescriptors.OrderBy(filter => filter,FilterDescriptorOrderComparer.Comparer).ToList();
- // 省略....
- return new FilterFactoryResult(staticFilterItems, filters);
- }
保留了关键的一句话, 那就是根据 actionDescriptor 来获取到它对应的所有 Filter(无论是针对全局, Controller 还是 Action), 然后对这些 Filter 进行排序, 这里用到了排序方法 FilterDescriptorOrderComparer, 它用来定义 Filter 的执行顺序, 详细内容见后文.
五, Filter 的执行
Filter 的执行在 invoker 的执行阶段, 会进入 InvokeFilterPipelineAsync, 在这里, 各种 Filter 按照图一的方式逐一被执行. 具体内容上一章已经进行了详细的描述. 它是通过两个 while 循环实现了如图一的顺序逐一执行.
- while (!isCompleted)
- {
- await Next(ref next, ref scope, ref state, ref isCompleted);
- }
具体不再赘述.
六, Filter 的执行顺序
Filter 的执行顺序由三部分决定:
1. 对于不同种的 Filter, 按照图一的顺序执行, 例如 Authorization filters 会最先被执行.
2. 对于同种的 Filter, 执行顺序由其 Order 和 Scope 来决定.
在 Filter 的获取一节提到了 Filter 的排序方法 FilterDescriptorOrderComparer, 它拥有对 Filter 定的排序.
- public class FilterDescriptorOrderComparer : IComparer<FilterDescriptor>
- {
- public static FilterDescriptorOrderComparer Comparer { get; } = new FilterDescriptorOrderComparer();
- public int Compare(FilterDescriptor x, FilterDescriptor y)
- {
- if (x == null)
- {
- throw new ArgumentNullException(nameof(x));
- }
- if (y == null)
- {
- throw new ArgumentNullException(nameof(y));
- }
- if (x.Order == y.Order)
- {
- return x.Scope.CompareTo(y.Scope);
- }
- else
- {
- return x.Order.CompareTo(y.Order);
- }
- }
- }
从这个方法可以看到 Filter 的执行顺序, 按照先 Order 后 Scope 的方式排序. 对于继承默认的内置 Filter 的, Order 默认为 0, 所有对于这样的 Filter 来说觉得他们顺序的是 Scope, 也就是作用域, 默认情况下, 全局的为 10,Controller 上的为 20,Action 上的为 30. 也就是说, Filter 的执行顺序为
全局 -> Controller -> Action, 实际的执行顺序是这样的:
全局 OnActionExecuting
- Controller OnActionExecuting
- Action OnActionExecuting
- Action OnActionExecuted
- Controller OnActionExecuted
全局 OnActionExecuted
也是嵌套的, 和中间件的处理方式类似.
当然我们可以自定义 Filter 的 Order 使其不再采用默认值 0, 只需在其构造函数中设置即可
- public class Test1Filter : ActionFilterAttribute
- {
- public Test1Filter()
- {
- Order = 1;
- }
- //...........
- }
3. 对于同样作用域的同种 Filter 来说, 它们的执行顺序是按照注册先后排列的.
例如:
- [Test2Filter]
- [Test1Filter]
- public JsonResult Index()
则先执行 Test2Filter, 后执行 Test1Filter.
来源: https://www.cnblogs.com/FlyLolo/p/ASPNETCore2_18.html