四、Filter的获取
Filter的获取是在FilterFactory的GetAllFilters方法中,
1. 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。