C.泳道三:ControllerActionInvokerProvider.OnProvidersExecuting(context)
即泳道二中的③的详细描述
1 public void OnProvidersExecuting(ActionInvokerProviderContext context) 2 { 3 if (context.ActionContext.ActionDescriptor is ControllerActionDescriptor) 4 { 5 var controllerContext = new ControllerContext(context.ActionContext); 6 // PERF: These are rarely going to be changed, so let's go copy-on-write. 7 controllerContext.ValueProviderFactories = new CopyOnWriteList<IValueProviderFactory>(_valueProviderFactories); 8 controllerContext.ModelState.MaxAllowedErrors = _maxModelValidationErrors; 9 10 var cacheResult = _controllerActionInvokerCache.GetCachedResult(controllerContext); 11 12 var invoker = new ControllerActionInvoker( 13 _logger, 14 _diagnosticSource, 15 _mapper, 16 controllerContext, 17 cacheResult.cacheEntry, 18 cacheResult.filters); 19 20 context.Result = invoker; 21 } 22 }
如上文所述,在处理之前,首先就是判断当前action是否是自己对应处理的类型。然后就是继续封装大法,将ActionContext封装成了ControllerContext。进而是调用GetCachedResult方法读取两个关键内容cacheResult.cacheEntry和cacheResult.filters后,将其封装成ControllerActionInvoker(⑤)。
D.第四条泳道:
对应的是第三条中的④ControllerActionInvokerCache.GetCachedResult(controllerContext);
1 public (ControllerActionInvokerCacheEntry cacheEntry, IFilterMetadata[] filters) GetCachedResult(ControllerContext controllerContext) 2 { 3 var cache = CurrentCache; 4 var actionDescriptor = controllerContext.ActionDescriptor; 5 6 IFilterMetadata[] filters; 7 if (!cache.Entries.TryGetValue(actionDescriptor, out var cacheEntry)) 8 { 9 var filterFactoryResult = FilterFactory.GetAllFilters(_filterProviders, controllerContext); 10 filters = filterFactoryResult.Filters; 11 12 var parameterDefaultValues = ParameterDefaultValues 13 .GetParameterDefaultValues(actionDescriptor.MethodInfo); 14 15 var objectMethodExecutor = ObjectMethodExecutor.Create( 16 actionDescriptor.MethodInfo, 17 actionDescriptor.ControllerTypeInfo, 18 parameterDefaultValues); 19 20 var controllerFactory = _controllerFactoryProvider.CreateControllerFactory(actionDescriptor); 21 var controllerReleaser = _controllerFactoryProvider.CreateControllerReleaser(actionDescriptor); 22 var propertyBinderFactory = ControllerBinderDelegateProvider.CreateBinderDelegate( 23 _parameterBinder, 24 _modelBinderFactory, 25 _modelMetadataProvider, 26 actionDescriptor, 27 _mvcOptions); 28 29 var actionMethodExecutor = ActionMethodExecutor.GetExecutor(objectMethodExecutor); 30 31 cacheEntry = new ControllerActionInvokerCacheEntry( 32 filterFactoryResult.CacheableFilters, 33 controllerFactory, 34 controllerReleaser, 35 propertyBinderFactory, 36 objectMethodExecutor, 37 actionMethodExecutor); 38 cacheEntry = cache.Entries.GetOrAdd(actionDescriptor, cacheEntry); 39 } 40 else 41 { 42 // Filter instances from statically defined filter descriptors + from filter providers 43 filters = FilterFactory.CreateUncachedFilters(_filterProviders, controllerContext, cacheEntry.CachedFilters); 44 } 45 46 return (cacheEntry, filters);
总的来看,本段内容主要是为了组装cacheEntry和 filters两个内容,而一个大的 if 体现出这里加入了缓存机制,使系统不必每次都去拼凑这些,提高执行效率。
⑥IFilterMetadata[] filters,它是一个filter的集和,首先调用FilterFactory的GetAllFilters(_filterProviders, controllerContext)方法获取当前action对应的所有Filter并对这些Filter进行排序(Filter部分将在之后章节分享)。
接下来就是组装⑦cacheEntry,它的内容比较多,比较重要的几个有:⑧ controllerFactory和controllerReleaser他们的本质都是Func<ControllerContext, object>,也就是Controller的Create和Release方法。 ⑨propertyBinderFactory 是一个用于参数绑定的Task,可以说也是一个组装好准备被执行的方法。最后一个⑩actionMethodExecutor也就是执行者,通过ActionMethodExecutor.GetExecutor(objectMethodExecutor)方法从众多的action执行者(如图二)中找出一个当前action对应的执行者出来。
图二
总结: 本节invoker的生成,总的来说就是一个执行前“万事俱备”的过程,invoker是一个组装起来的集合,它包含一个人(执行者actionMethodExecutor)、N把枪(组装好用于“被执行”的方法例如controllerFactory、controllerReleaser和propertyBinderFactory,当然还有个filter的集和)。由此也可以进一步想到,接下来的过程就是这些准备好的内容按照一定的顺序逐步执行的过程。
二、invoker的执行
invoker的执行也就是invoker.InvokeAsync(),虽然invoker本质上是ControllerActionInvoker,但这个方法写在ResourceInvoker类中, ControllerActionInvoker : ResourceInvoker, IActionInvoker 。
public virtual async Task InvokeAsync() { try { await InvokeFilterPipelineAsync(); } finally { ReleaseResources(); _logger.ExecutedAction(_actionContext.ActionDescriptor, stopwatch.GetElapsedTime()); } } private async Task InvokeFilterPipelineAsync() { var next = State.InvokeBegin; var scope = Scope.Invoker; var state = (object)null; // `isCompleted` will be set to true when we've reached a terminal state. var isCompleted = false; while (!isCompleted) { await Next(ref next, ref scope, ref state, ref isCompleted); } }
看似比较简单的两个方法,从InvokeAsync方法中可以看出来,请求会进入筛选器管道进行处理,也就是 Task InvokeFilterPipelineAsync() 方法,借用官方文档中的一个图看一下
图三
此图描述了请求经过其他中间件处理后,进入路由处理最终找到了对应的action,最终进入筛选器管道进行处理。而这个处理的核心部分就是方法中的 while (!isCompleted) 循环,它对应的Next方法比较长,如下(较长已折叠)