Error message here!

Hide Error message here!

忘记密码?

Error message here!

请输入正确邮箱

Hide Error message here!

密码丢失?请输入您的电子邮件地址。您将收到一个重设密码链接。

Error message here!

返回登录

Close

ASP.NET Core 2.2 : 十七.Action的执行(Endpoint.RequestDelegate后面的故事)

FlyLolo 2019-01-25 11:58:00 阅读数:214 评论数:0 点赞数:0 收藏数:0

          上一章介绍了经过路由的处理,一个请求找到了具体处理这个请求的EndPoint,并最终执行它的RequestDelegate方法来处理这个Httpcontext。本章继续这个处理进程,按照惯例,依然通过几幅图来聊一聊这个RequestDelegate之后的故事。在此就避免不了的聊到各种Filter,它方便我们在action执行的前后做一些 “小动作”。(ASP.NET Core 系列目录

一、概述

          首先看一下RequestDelegate这个方法:RequestDelegate requestDelegate = (context) =>{var routeData =context.GetRouteData();var actionContext = newActionContext(context, routeData, action);var invoker =_invokerFactory.CreateInvoker(actionContext);returninvoker.InvokeAsync(); };

          将这个方法的内容分为两部分:

          A. invoker的生成,前三句,通过CreateInvoker方法生成了一个invoker,它是一个比较复杂的综合体,包含了controller的创建工厂、参数的绑定方法以及本action相关的各种Filter的集合等, 也就是说它是前期准备工作阶段,这个阶段扩展开来涉及面比较广,在下文详细描述。  

          B.invoker的执行,最后一句,前面已经万事俱备,准备了好多方法,到此来执行。此时涉及到前面准备的各种方法的执行,各种Filter也在此时被执行。

二、invoker的生成

           依照习惯,还是通过流程图来看一看:

![](https://img2018.cnblogs.com/blog/548134/201901/548134-20190125115548360-1143760105.png)

                                                                                                     图一(点击查看大图

          首先说一下此图的结构,每个泳道相当于是上一个泳道中的图标的细化说明,例如第二条泳道是图标①标识的方块的明细化。

          A. 泳道一:

                  就是第一节【概述】中描述的的内容,不再赘述。另外提一下本文的核心invoker本质上就是一个ControllerActionInvoker,也是图中的ActionInvokerProviderContext.Result。

          B.泳道二:即①的详细描述

          ① ActionInvokerFactory.CreateInvoker(actionContext)1 publicIActionInvoker CreateInvoker(ActionContext actionContext)2 {3 var context = newActionInvokerProviderContext(actionContext);4 5 foreach (var provider inactionInvokerProviders)6 {7 provider.OnProvidersExecuting(context);8 }9 10 for (var i = actionInvokerProviders.Length - 1; i >= 0; i--)11 {12 _actionInvokerProviders[i].OnProvidersExecuted(context);13 }14 15 returncontext.Result;16 }

          本章设计的这部分内容比较常见的一个操作就是context的封装,这从第一个泳道的第一个操作就开始了, 他将HttpContext、RouteData,ActionDescriptor封装到一起成了一个ActionContext ,而到了这个方法,又将这个ActionContext封装成了ActionInvokerProviderContext,接下来就是遍历_actionInvokerProviders调用它们的OnProvidersExecuting和OnProvidersExecuted方法来设置**ActionInvokerProviderContext**.Result,也就是最终的ControllerActionInvoker。

          这里说一下_actionInvokerProviders,它的类型是IActionInvokerProvider[],默认情况下包含了两个,分别是ControllerActionInvokerProvider和PageActionInvokerProvider,第一个是用于MVC的action的处理,而第二个用于Razor Pages Web的处理。二者的OnProvidersExecuting方法都会首先判断当前action是不是自己对应的类型,若不是则直接跳过。二者的OnProvidersExecuted方法目前均为空。所以图中和下面关于OnProvidersExecuting的描述也仅限于ControllerActionInvokerProvider的OnProvidersExecuting方法。

          C.泳道三:ControllerActionInvokerProvider.OnProvidersExecuting(context)

          即泳道二中的③的详细描述1 public voidOnProvidersExecuting(ActionInvokerProviderContext context)2 {3 if (context.ActionContext.ActionDescriptor isControllerActionDescriptor)4 {5 var controllerContext = newControllerContext(context.ActionContext);6 //PERF: These are rarely going to be changed, so let's go copy-on-write. 7 controllerContext.ValueProviderFactories = new CopyOnWriteList(valueProviderFactories);8 controllerContext.ModelState.MaxAllowedErrors =maxModelValidationErrors;9 10 var cacheResult =controllerActionInvokerCache.GetCachedResult(controllerContext);11 12 var invoker = newControllerActionInvoker(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 varcacheEntry))8 {9 var filterFactoryResult =FilterFactory.GetAllFilters(_filterProviders, controllerContext);10 filters =filterFactoryResult.Filters;11 12 var parameterDefaultValues =ParameterDefaultValues13 .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 = newControllerActionInvokerCacheEntry(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,也就是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 asyncTask InvokeAsync() {try{awaitInvokeFilterPipelineAsync(); }finally{ ReleaseResources(); logger.ExecutedAction(actionContext.ActionDescriptor, stopwatch.GetElapsedTime()); } }private asyncTask 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, refisCompleted); } }

看似比较简单的两个方法,从InvokeAsync方法中可以看出来,请求会进入筛选器管道进行处理,也就是 Task InvokeFilterPipelineAsync() 方法,借用官方文档中的一个图看一下

                                  图三

此图描述了请求经过其他中间件处理后,进入路由处理最终找到了对应的action,最终进入筛选器管道进行处理。而这个处理的核心部分就是方法中的 while (!isCompleted) 循环,它对应的Next方法比较长,如下(较长已折叠)

1 private Task Next(ref State next, ref Scope scope, ref object state, ref boolisCompleted)2 {3 switch(next)4 {5 caseState.InvokeBegin:6 {7 goto caseState.AuthorizationBegin;8 }9 10 caseState.AuthorizationBegin:11 {12 cursor.Reset();13 goto caseState.AuthorizationNext;14 }15 16 caseState.AuthorizationNext:17 {18 var current = cursor.GetNextFilter();19 if (current.FilterAsync != null)20 {21 if (authorizationContext == null)22 {23 authorizationContext = newAuthorizationFilterContext(actionContext, filters);24 }25 26 state =current.FilterAsync;27 goto caseState.AuthorizationAsyncBegin;28 }29 else if (current.Filter != null)30 {31 if (authorizationContext == null)32 {33 authorizationContext = newAuthorizationFilterContext(actionContext, filters);34 }35 36 state =current.Filter;37 goto caseState.AuthorizationSync;38 }39 else 40 {41 goto caseState.AuthorizationEnd;42 }43 }44 45 caseState.AuthorizationAsyncBegin:46 {47 Debug.Assert(state != null);48 Debug.Assert(authorizationContext != null);49 50 var filter =(IAsyncAuthorizationFilter)state;51 var authorizationContext =authorizationContext;52 53 diagnosticSource.BeforeOnAuthorizationAsync(authorizationContext, filter);54 logger.BeforeExecutingMethodOnFilter(55 FilterTypeConstants.AuthorizationFilter,56 nameof(IAsyncAuthorizationFilter.OnAuthorizationAsync),57 filter);58 59 var task =filter.OnAuthorizationAsync(authorizationContext);60 if (task.Status !=TaskStatus.RanToCompletion)61 {62 next =State.AuthorizationAsyncEnd;63 returntask;64 }65 66 goto caseState.AuthorizationAsyncEnd;67 }68 69 caseState.AuthorizationAsyncEnd:70 {71 Debug.Assert(state != null);72 Debug.Assert(authorizationContext != null);73 74 var filter =(IAsyncAuthorizationFilter)state;75 var authorizationContext =authorizationContext;76 77 diagnosticSource.AfterOnAuthorizationAsync(authorizationContext, filter);78 logger.AfterExecutingMethodOnFilter(79 FilterTypeConstants.AuthorizationFilter,80 nameof(IAsyncAuthorizationFilter.OnAuthorizationAsync),81 filter);82 83 if (authorizationContext.Result != null)84 {85 goto caseState.AuthorizationShortCircuit;86 }87 88 goto caseState.AuthorizationNext;89 }90 91 caseState.AuthorizationSync:92 {93 Debug.Assert(state != null);94 Debug.Assert(authorizationContext != null);95 96 var filter =(IAuthorizationFilter)state;97 var authorizationContext =authorizationContext;98 99 diagnosticSource.BeforeOnAuthorization(authorizationContext, filter);100 logger.BeforeExecutingMethodOnFilter(101 FilterTypeConstants.AuthorizationFilter,102 nameof(IAuthorizationFilter.OnAuthorization),103 filter);104 105 filter.OnAuthorization(authorizationContext);106 107 diagnosticSource.AfterOnAuthorization(authorizationContext, filter);108 logger.AfterExecutingMethodOnFilter(109 FilterTypeConstants.AuthorizationFilter,110 nameof(IAuthorizationFilter.OnAuthorization),111 filter);112 113 if (authorizationContext.Result != null)114 {115 goto caseState.AuthorizationShortCircuit;116 }117 118 goto caseState.AuthorizationNext;119 }120 121 caseState.AuthorizationShortCircuit:122 {123 Debug.Assert(state != null);124 Debug.Assert(authorizationContext != null);125 Debug.Assert(authorizationContext.Result != null);126 127 logger.AuthorizationFailure((IFilterMetadata)state);128 129 //This is a short-circuit - execute relevant result filters + result and complete this invocation. 130 isCompleted = true;131 result =authorizationContext.Result;132 returnInvokeAlwaysRunResultFilters();133 }134 135 caseState.AuthorizationEnd:136 {137 goto caseState.ResourceBegin;138 }139 140 caseState.ResourceBegin:141 {142 cursor.Reset();143 goto caseState.ResourceNext;144 }145 146 caseState.ResourceNext:147 {148 var current = cursor.GetNextFilter();149 if (current.FilterAsync != null)150 {151 if (resourceExecutingContext == null)152 {153 resourceExecutingContext = newResourceExecutingContext(154 actionContext,155 filters,156 valueProviderFactories);157 }158 159 state =current.FilterAsync;160 goto caseState.ResourceAsyncBegin;161 }162 else if (current.Filter != null)163 {164 if (resourceExecutingContext == null)165 {166 resourceExecutingContext = newResourceExecutingContext(167 actionContext,168 filters,169 valueProviderFactories);170 }171 172 state =current.Filter;173 goto caseState.ResourceSyncBegin;174 }175 else 176 {177 //All resource filters are currently on the stack - now execute the 'inside'. 178 goto caseState.ResourceInside;179 }180 }181 182 caseState.ResourceAsyncBegin:183 {184 Debug.Assert(state != null);185 Debug.Assert(resourceExecutingContext != null);186 187 var filter =(IAsyncResourceFilter)state;188 var resourceExecutingContext =resourceExecutingContext;189 190 diagnosticSource.BeforeOnResourceExecution(resourceExecutingContext, filter);191 logger.BeforeExecutingMethodOnFilter(192 FilterTypeConstants.ResourceFilter,193 nameof(IAsyncResourceFilter.OnResourceExecutionAsync),194 filter);195 196 var task =filter.OnResourceExecutionAsync(resourceExecutingContext, InvokeNextResourceFilterAwaitedAsync);197 if (task.Status !=TaskStatus.RanToCompletion)198 {199 next =State.ResourceAsyncEnd;200 returntask;201 }202 203 goto caseState.ResourceAsyncEnd;204 }205 206 caseState.ResourceAsyncEnd:207 {208 Debug.Assert(state != null);209 Debug.Assert(resourceExecutingContext != null);210 211 var filter =(IAsyncResourceFilter)state;212 if (resourceExecutedContext == null)213 {214 //If we get here then the filter didn't call 'next' indicating a short circuit. 215 resourceExecutedContext = newResourceExecutedContext(resourceExecutingContext, filters)216 {217 Canceled = true,218 Result =resourceExecutingContext.Result,219 };220 221 diagnosticSource.AfterOnResourceExecution(resourceExecutedContext, filter);222 logger.AfterExecutingMethodOnFilter(223 FilterTypeConstants.ResourceFilter,224 nameof(IAsyncResourceFilter.OnResourceExecutionAsync),225 filter);226 227 //A filter could complete a Task without setting a result 228 if (resourceExecutingContext.Result != null)229 {230 goto caseState.ResourceShortCircuit;231 }232 }233 234 goto caseState.ResourceEnd;235 }236 237 caseState.ResourceSyncBegin:238 {239 Debug.Assert(state != null);240 Debug.Assert(resourceExecutingContext != null);241 242 var filter =(IResourceFilter)state;243 var resourceExecutingContext =resourceExecutingContext;244 245 diagnosticSource.BeforeOnResourceExecuting(resourceExecutingContext, filter);246 logger.BeforeExecutingMethodOnFilter(247 FilterTypeConstants.ResourceFilter,248 nameof(IResourceFilter.OnResourceExecuting),249 filter);250 251 filter.OnResourceExecuting(resourceExecutingContext);252 253 diagnosticSource.AfterOnResourceExecuting(resourceExecutingContext, filter);254 logger.AfterExecutingMethodOnFilter(255 FilterTypeConstants.ResourceFilter,256 nameof(IResourceFilter.OnResourceExecuting),257 filter);258 259 if (resourceExecutingContext.Result != null)260 {261 resourceExecutedContext = newResourceExecutedContext(resourceExecutingContext, filters)262 {263 Canceled = true,264 Result =resourceExecutingContext.Result,265 };266 267 goto caseState.ResourceShortCircuit;268 }269 270 var task =InvokeNextResourceFilter();271 if (task.Status !=TaskStatus.RanToCompletion)272 {273 next =State.ResourceSyncEnd;274 returntask;275 }276 277 goto caseState.ResourceSyncEnd;278 }279 280 caseState.ResourceSyncEnd:281 {282 Debug.Assert(state != null);283 Debug.Assert(resourceExecutingContext != null);284 Debug.Assert(resourceExecutedContext != null);285 286 var filter =(IResourceFilter)state;287 var resourceExecutedContext =resourceExecutedContext;288 289 diagnosticSource.BeforeOnResourceExecuted(resourceExecutedContext, filter);290 logger.BeforeExecutingMethodOnFilter(291 FilterTypeConstants.ResourceFilter,292 nameof(IResourceFilter.OnResourceExecuted),293 filter);294 295 filter.OnResourceExecuted(resourceExecutedContext);296 297 diagnosticSource.AfterOnResourceExecuted(resourceExecutedContext, filter);298 logger.AfterExecutingMethodOnFilter(299 FilterTypeConstants.ResourceFilter,300 nameof(IResourceFilter.OnResourceExecuted),301 filter);302 303 goto caseState.ResourceEnd;304 }305 306 caseState.ResourceShortCircuit:307 {308 Debug.Assert(state != null);309 Debug.Assert(resourceExecutingContext != null);310 Debug.Assert(resourceExecutedContext != null);311 312 logger.ResourceFilterShortCircuited((IFilterMetadata)state);313 314 result =resourceExecutingContext.Result;315 var task =InvokeAlwaysRunResultFilters();316 if (task.Status !=TaskStatus.RanToCompletion)317 {318 next =State.ResourceEnd;319 returntask;320 }321 322 goto caseState.ResourceEnd;323 }324 325 caseState.ResourceInside:326 {327 goto caseState.ExceptionBegin;328 }329 330 caseState.ExceptionBegin:331 {332 cursor.Reset();333 goto caseState.ExceptionNext;334 }335 336 caseState.ExceptionNext:337 {338 var current = cursor.GetNextFilter();339 if (current.FilterAsync != null)340 {341 state =current.FilterAsync;342 goto caseState.ExceptionAsyncBegin;343 }344 else if (current.Filter != null)345 {346 state =current.Filter;347 goto caseState.ExceptionSyncBegin;348 }349 else if (scope ==Scope.Exception)350 {351 //All exception filters are on the stack already - so execute the 'inside'. 352 goto caseState.ExceptionInside;353 }354 else 355 {356 //There are no exception filters - so jump right to the action. 357 Debug.Assert(scope == Scope.Invoker || scope ==Scope.Resource);358 goto caseState.ActionBegin;359 }360 }361 362 caseState.ExceptionAsyncBegin:363 {364 var task =InvokeNextExceptionFilterAsync();365 if (task.Status !=TaskStatus.RanToCompletion)366 {367 next =State.ExceptionAsyncResume;368 returntask;369 }370 371 goto caseState.ExceptionAsyncResume;372 }373 374 caseState.ExceptionAsyncResume:375 {376 Debug.Assert(state != null);377 378 var filter =(IAsyncExceptionFilter)state;379 var exceptionContext =exceptionContext;380 381 //When we get here we're 'unwinding' the stack of exception filters. If we have an unhandled exception,382 //we'll call the filter. Otherwise there's nothing to do. 383 if (exceptionContext?.Exception != null && !exceptionContext.ExceptionHandled)384 {385 diagnosticSource.BeforeOnExceptionAsync(exceptionContext, filter);386 logger.BeforeExecutingMethodOnFilter(387 FilterTypeConstants.ExceptionFilter,388 nameof(IAsyncExceptionFilter.OnExceptionAsync),389 filter);390 391 var task =filter.OnExceptionAsync(exceptionContext);392 if (task.Status !=TaskStatus.RanToCompletion)393 {394 next =State.ExceptionAsyncEnd;395 returntask;396 }397 398 goto caseState.ExceptionAsyncEnd;399 }400 401 goto caseState.ExceptionEnd;402 }403 404 caseState.ExceptionAsyncEnd:405 {406 Debug.Assert(state != null);407 Debug.Assert(exceptionContext != null);408 409 var filter =(IAsyncExceptionFilter)state;410 var exceptionContext =exceptionContext;411 412 diagnosticSource.AfterOnExceptionAsync(exceptionContext, filter);413 logger.AfterExecutingMethodOnFilter(414 FilterTypeConstants.ExceptionFilter,415 nameof(IAsyncExceptionFilter.OnExceptionAsync),416 filter);417 418 if (exceptionContext.Exception == null ||exceptionContext.ExceptionHandled)419 {420 //We don't need to do anything to trigger a short circuit. If there's another421 //exception filter on the stack it will check the same set of conditions422 //and then just skip itself. 423 logger.ExceptionFilterShortCircuited(filter);424 }425 426 goto caseState.ExceptionEnd;427 }428 429 caseState.ExceptionSyncBegin:430 {431 var task =InvokeNextExceptionFilterAsync();432 if (task.Status !=TaskStatus.RanToCompletion)433 {434 next =State.ExceptionSyncEnd;435 returntask;436 }437 438 goto caseState.ExceptionSyncEnd;439 }440 441 caseState.ExceptionSyncEnd:442 {443 Debug.Assert(state != null);444 445 var filter =(IExceptionFilter)state;446 var exceptionContext =exceptionContext;447 448 //When we get here we're 'unwinding' the stack of exception filters. If we have an unhandled exception,449 //we'll call the filter. Otherwise there's nothing to do. 450 if (exceptionContext?.Exception != null && !exceptionContext.ExceptionHandled)451 {452 diagnosticSource.BeforeOnException(exceptionContext, filter);453 logger.BeforeExecutingMethodOnFilter(454 FilterTypeConstants.ExceptionFilter,455 nameof(IExceptionFilter.OnException),456 filter);457 458 filter.OnException(exceptionContext);459 460 diagnosticSource.AfterOnException(exceptionContext, filter);461 logger.AfterExecutingMethodOnFilter(462 FilterTypeConstants.ExceptionFilter,463 nameof(IExceptionFilter.OnException),464 filter);465 466 if (exceptionContext.Exception == null ||exceptionContext.ExceptionHandled)467 {468 //We don't need to do anything to trigger a short circuit. If there's another469 //exception filter on the stack it will check the same set of conditions470 //and then just skip itself. 471 logger.ExceptionFilterShortCircuited(filter);472 }473 }474 475 goto caseState.ExceptionEnd;476 }477 478 caseState.ExceptionInside:479 {480 goto caseState.ActionBegin;481 }482 483 caseState.ExceptionHandled:484 {485 //We arrive in this state when an exception happened, but was handled by exception filters486 //either by setting ExceptionHandled, or nulling out the Exception or setting a result487 //on the ExceptionContext.488 // 489 //We need to execute the result (if any) and then exit gracefully which unwinding Resource490 //filters. 491 492 Debug.Assert(state != null);493 Debug.Assert(exceptionContext != null);494 495 if (exceptionContext.Result == null)496 {497 exceptionContext.Result = newEmptyResult();498 }499 500 result =exceptionContext.Result;501 502 var task =InvokeAlwaysRunResultFilters();503 if (task.Status !=TaskStatus.RanToCompletion)504 {505 next =State.ResourceInsideEnd;506 returntask;507 }508 509 goto caseState.ResourceInsideEnd;510 }511 512 caseState.ExceptionEnd:513 {514 var exceptionContext =exceptionContext;515 516 if (scope ==Scope.Exception)517 {518 isCompleted = true;519 returnTask.CompletedTask;520 }521 522 if (exceptionContext != null)523 {524 if (exceptionContext.Result != null || 525 exceptionContext.Exception == null || 526 exceptionContext.ExceptionHandled)527 {528 goto caseState.ExceptionHandled;529 }530 531 Rethrow(exceptionContext);532 Debug.Fail("unreachable");533 }534 535 var task =InvokeResultFilters();536 if (task.Status !=TaskStatus.RanToCompletion)537 {538 next =State.ResourceInsideEnd;539 returntask;540 }541 goto caseState.ResourceInsideEnd;542 }543 544 caseState.ActionBegin:545 {546 var task =InvokeInnerFilterAsync();547 if (task.Status !=TaskStatus.RanToCompletion)548 {549 next =State.ActionEnd;550 returntask;551 }552 553 goto caseState.ActionEnd;554 }555 556 caseState.ActionEnd:557 {558 if (scope ==Scope.Exception)559 {560 //If we're inside an exception filter, let's allow those filters to 'unwind' before561 //the result. 562 isCompleted = true;563 returnTask.CompletedTask;564 }565 566 Debug.Assert(scope == Scope.Invoker || scope ==Scope.Resource);567 var task =InvokeResultFilters();568 if (task.Status !=TaskStatus.RanToCompletion)569 {570 next =State.ResourceInsideEnd;571 returntask;572 }573 goto caseState.ResourceInsideEnd;574 }575 576 caseState.ResourceInsideEnd:577 {578 if (scope ==Scope.Resource)579 {580 resourceExecutedContext = newResourceExecutedContext(actionContext, filters)581 {582 Result =result,583 };584 585 goto caseState.ResourceEnd;586 }587 588 goto caseState.InvokeEnd;589 }590 591 caseState.ResourceEnd:592 {593 if (scope ==Scope.Resource)594 {595 isCompleted = true;596 returnTask.CompletedTask;597 }598 599 Debug.Assert(scope ==Scope.Invoker);600 Rethrow(_resourceExecutedContext);601 602 goto caseState.InvokeEnd;603 }604 605 caseState.InvokeEnd:606 {607 isCompleted = true;608 returnTask.CompletedTask;609 }610 611 default:612 throw newInvalidOperationException();613 }614 }View Code

从代码可以看出,它是根据状态State进行轮转,而执行顺序是Authorization->Resource->Exception......  也就是说当前action对应的多种类型的Filter会按照这样的顺序被执行,如下图

            图四

可以看出,在上面几个Filter执行之后,ActionFilter的执行比较特殊,它将Action的执行包在了中间,这段逻辑写在了ControllerActionInvoker自己的类中,同样是一个 Task Next 方法被while循环调用,如下

1 private Task Next(ref State next, ref Scope scope, ref object state, ref boolisCompleted)2 {3 switch(next)4 {5 caseState.ActionBegin:6 {7 var controllerContext =controllerContext;8 9 cursor.Reset();10 11 instance =cacheEntry.ControllerFactory(controllerContext);12 13 arguments = new Dictionary(StringComparer.OrdinalIgnoreCase);14 15 var task =BindArgumentsAsync();16 if (task.Status !=TaskStatus.RanToCompletion)17 {18 next =State.ActionNext;19 returntask;20 }21 22 goto caseState.ActionNext;23 }24 25 caseState.ActionNext:26 {27 var current = cursor.GetNextFilter();28 if (current.FilterAsync != null)29 {30 if (actionExecutingContext == null)31 {32 actionExecutingContext = newActionExecutingContext(controllerContext, filters, arguments, instance);33 }34 35 state =current.FilterAsync;36 goto caseState.ActionAsyncBegin;37 }38 else if (current.Filter != null)39 {40 if (actionExecutingContext == null)41 {42 actionExecutingContext = newActionExecutingContext(controllerContext, filters, arguments, instance);43 }44 45 state =current.Filter;46 goto caseState.ActionSyncBegin;47 }48 else 49 {50 goto caseState.ActionInside;51 }52 }53 54 caseState.ActionAsyncBegin:55 {56 Debug.Assert(state != null);57 Debug.Assert(actionExecutingContext != null);58 59 var filter =(IAsyncActionFilter)state;60 var actionExecutingContext =actionExecutingContext;61 62 diagnosticSource.BeforeOnActionExecution(actionExecutingContext, filter);63 logger.BeforeExecutingMethodOnFilter(64 MvcCoreLoggerExtensions.ActionFilter,65 nameof(IAsyncActionFilter.OnActionExecutionAsync),66 filter);67 68 var task =filter.OnActionExecutionAsync(actionExecutingContext, InvokeNextActionFilterAwaitedAsync);69 if (task.Status !=TaskStatus.RanToCompletion)70 {71 next =State.ActionAsyncEnd;72 returntask;73 }74 75 goto caseState.ActionAsyncEnd;76 }77 78 caseState.ActionAsyncEnd:79 {80 Debug.Assert(state != null);81 Debug.Assert(actionExecutingContext != null);82 83 var filter =(IAsyncActionFilter)state;84 85 if (actionExecutedContext == null)86 {87 //If we get here then the filter didn't call 'next' indicating a short circuit. 88 logger.ActionFilterShortCircuited(filter);89 90 actionExecutedContext = newActionExecutedContext(91 controllerContext,92 filters,93 instance)94 {95 Canceled = true,96 Result =actionExecutingContext.Result,97 };98 }99 100 diagnosticSource.AfterOnActionExecution(actionExecutedContext, filter);101 logger.AfterExecutingMethodOnFilter(102 MvcCoreLoggerExtensions.ActionFilter,103 nameof(IAsyncActionFilter.OnActionExecutionAsync),104 filter);105 106 goto caseState.ActionEnd;107 }108 109 caseState.ActionSyncBegin:110 {111 Debug.Assert(state != null);112 Debug.Assert(actionExecutingContext != null);113 114 var filter =(IActionFilter)state;115 var actionExecutingContext =actionExecutingContext;116 117 diagnosticSource.BeforeOnActionExecuting(actionExecutingContext, filter);118 logger.BeforeExecutingMethodOnFilter(119 MvcCoreLoggerExtensions.ActionFilter,120 nameof(IActionFilter.OnActionExecuting),121 filter);122 123 filter.OnActionExecuting(actionExecutingContext);124 125 diagnosticSource.AfterOnActionExecuting(actionExecutingContext, filter);126 logger.AfterExecutingMethodOnFilter(127 MvcCoreLoggerExtensions.ActionFilter,128 nameof(IActionFilter.OnActionExecuting),129 filter);130 131 if (actionExecutingContext.Result != null)132 {133 //Short-circuited by setting a result. 134 logger.ActionFilterShortCircuited(filter);135 136 actionExecutedContext = newActionExecutedContext(137 actionExecutingContext,138 filters,139 instance)140 {141 Canceled = true,142 Result =actionExecutingContext.Result,143 };144 145 goto caseState.ActionEnd;146 }147 148 var task =InvokeNextActionFilterAsync();149 if (task.Status !=TaskStatus.RanToCompletion)150 {151 next =State.ActionSyncEnd;152 returntask;153 }154 155 goto caseState.ActionSyncEnd;156 }157 158 caseState.ActionSyncEnd:159 {160 Debug.Assert(state != null);161 Debug.Assert(actionExecutingContext != null);162 Debug.Assert(actionExecutedContext != null);163 164 var filter =(IActionFilter)state;165 var actionExecutedContext =actionExecutedContext;166 167 diagnosticSource.BeforeOnActionExecuted(actionExecutedContext, filter);168 logger.BeforeExecutingMethodOnFilter(169 MvcCoreLoggerExtensions.ActionFilter,170 nameof(IActionFilter.OnActionExecuted),171 filter);172 173 filter.OnActionExecuted(actionExecutedContext);174 175 diagnosticSource.AfterOnActionExecuted(actionExecutedContext, filter);176 logger.AfterExecutingMethodOnFilter(177 MvcCoreLoggerExtensions.ActionFilter,178 nameof(IActionFilter.OnActionExecuted),179 filter);180 181 goto caseState.ActionEnd;182 }183 184 caseState.ActionInside:185 {186 var task =InvokeActionMethodAsync();187 if (task.Status !=TaskStatus.RanToCompletion)188 {189 next =State.ActionEnd;190 returntask;191 }192 193 goto caseState.ActionEnd;194 }195 196 caseState.ActionEnd:197 {198 if (scope ==Scope.Action)199 {200 if (actionExecutedContext == null)201 {202 actionExecutedContext = newActionExecutedContext(controllerContext, filters, instance)203 {204 Result =result,205 };206 }207 208 isCompleted = true;209 returnTask.CompletedTask;210 }211 212 var actionExecutedContext =actionExecutedContext;213 Rethrow(actionExecutedContext);214 215 if (actionExecutedContext != null)216 {217 result =actionExecutedContext.Result;218 }219 220 isCompleted = true;221 returnTask.CompletedTask;222 }223 224 default:225 throw newInvalidOperationException();226 }227 }View Code

而在ActionBegin的时候,通过ControllerFactory创建了Controller并调用 cacheEntry.ControllerBinderDelegate(controllerContext, instance, _arguments) 进行了参数绑定。

然后的顺序是   ActionFilter的OnActionExecuting方法 ->action的执行->ActionFilter的OnActionExecuted方法, action的执行如下:private asyncTask InvokeActionMethodAsync() {var controllerContext =controllerContext;var objectMethodExecutor =cacheEntry.ObjectMethodExecutor;var controller =instance;var arguments =arguments;var actionMethodExecutor =cacheEntry.ActionMethodExecutor;var orderedArguments =PrepareArguments(arguments, objectMethodExecutor);var diagnosticSource =diagnosticSource;var logger =logger; IActionResult result= null;try{ diagnosticSource.BeforeActionMethod( controllerContext, arguments, controller); logger.ActionMethodExecuting(controllerContext, orderedArguments);var stopwatch =ValueStopwatch.StartNew();var actionResultValueTask =actionMethodExecutor.Execute(mapper, objectMethodExecutor, controller, orderedArguments);if(actionResultValueTask.IsCompletedSuccessfully) { result=actionResultValueTask.Result; }else{ result= awaitactionResultValueTask; } _result=result; logger.ActionMethodExecuted(controllerContext, result, stopwatch.GetElapsedTime()); }finally{ diagnosticSource.AfterActionMethod( controllerContext, arguments, controllerContext, result); } }

 

总结: 如上文说的,本节的内容就是将准备阶段组装的多个方法在这里按一定的被逐步的执行(如图四)。

 

大概内容就是这样,详细分析起来涉及细节还有好多,后面的文章会对一些关键内容进行详细分享。

版权声明
本文为[FlyLolo]所创,转载请带上原文链接,感谢
https://www.cnblogs.com/FlyLolo/p/ASPNETCore2_17.html

编程之旅,人生之路,不止于编程,还有诗和远方。
阅代码原理,看框架知识,学企业实践;
赏诗词,读日记,踏人生之路,观世界之行;

支付宝红包,每日可领