public class ControllerActionInvoker : ResourceInvoker, IActionInvoker
我们知道,ControllerActionInvoker实现了IActionInvoker接口。然而却找不到InvokeAsync的方法实现。检查以后发现,它把实现放到了抽象类ResourceInvoker中了。那好吧,我们先来看看这个ResourceInvoker。
public virtual async Task InvokeAsync() { try { _diagnosticSource.BeforeAction( _actionContext.ActionDescriptor, _actionContext.HttpContext, _actionContext.RouteData); using (_logger.ActionScope(_actionContext.ActionDescriptor)) { _logger.ExecutingAction(_actionContext.ActionDescriptor); var startTimestamp = _logger.IsEnabled(LogLevel.Information) ? Stopwatch.GetTimestamp() : 0; try { //核心步骤 await InvokeFilterPipelineAsync(); } finally { ReleaseResources(); _logger.ExecutedAction(_actionContext.ActionDescriptor, startTimestamp); } } } finally { _diagnosticSource.AfterAction( _actionContext.ActionDescriptor, _actionContext.HttpContext, _actionContext.RouteData); } }
事实上,核心步骤就是执行过滤器管道。其他都是日志打印和诊断的内容。
private async Task InvokeFilterPipelineAsync() { var next = State.InvokeBegin; // The `scope` tells the `Next` method who the caller is, and what kind of state to initialize to // communicate a result. The outermost scope is `Scope.Invoker` and doesn't require any type // of context or result other than throwing. var scope = Scope.Invoker; // The `state` is used for internal state handling during transitions between states. In practice this // means storing a filter instance in `state` and then retrieving it in the next state. 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); } }
关键在于最后一个循环,其次是Next方法。这个方法比较长,我们一段一段来看。
private Task Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted) { switch (next) { case State.InvokeBegin: { goto case State.AuthorizationBegin; } case State.AuthorizationBegin: { _cursor.Reset(); goto case State.AuthorizationNext; } case State.AuthorizationNext: { var current = _cursor.GetNextFilter<IAuthorizationFilter, IAsyncAuthorizationFilter>(); if (current.FilterAsync != null) { if (_authorizationContext == null) { _authorizationContext = new AuthorizationFilterContext(_actionContext, _filters); } state = current.FilterAsync; goto case State.AuthorizationAsyncBegin; } else if (current.Filter != null) { if (_authorizationContext == null) { _authorizationContext = new AuthorizationFilterContext(_actionContext, _filters); } state = current.Filter; goto case State.AuthorizationSync; } else { goto case State.AuthorizationEnd; } }
我们看到,首先是一个大的Switch语句。Begin之后紧跟的就是Authorization,也就是说,整个过滤器管道第一步就是授权。但这里出现的都是一些前期准备。
case State.AuthorizationAsyncBegin: { Debug.Assert(state != null); Debug.Assert(_authorizationContext != null); var filter = (IAsyncAuthorizationFilter)state; var authorizationContext = _authorizationContext; _diagnosticSource.BeforeOnAuthorizationAsync(authorizationContext, filter); var task = filter.OnAuthorizationAsync(authorizationContext); if (task.Status != TaskStatus.RanToCompletion) { next = State.AuthorizationAsyncEnd; return task; } goto case State.AuthorizationAsyncEnd; } case State.AuthorizationAsyncEnd: { Debug.Assert(state != null); Debug.Assert(_authorizationContext != null); var filter = (IAsyncAuthorizationFilter)state; var authorizationContext = _authorizationContext; _diagnosticSource.AfterOnAuthorizationAsync(authorizationContext, filter); if (authorizationContext.Result != null) { goto case State.AuthorizationShortCircuit; } goto case State.AuthorizationNext; } case State.AuthorizationSync: { Debug.Assert(state != null); Debug.Assert(_authorizationContext != null); var filter = (IAuthorizationFilter)state; var authorizationContext = _authorizationContext; _diagnosticSource.BeforeOnAuthorization(authorizationContext, filter); filter.OnAuthorization(authorizationContext); _diagnosticSource.AfterOnAuthorization(authorizationContext, filter); if (authorizationContext.Result != null) { goto case State.AuthorizationShortCircuit; } goto case State.AuthorizationNext; } case State.AuthorizationShortCircuit: { Debug.Assert(state != null); Debug.Assert(_authorizationContext != null); _logger.AuthorizationFailure((IFilterMetadata)state); // If an authorization filter short circuits, the result is the last thing we execute // so just return that task instead of calling back into the state machine. isCompleted = true; return InvokeResultAsync(_authorizationContext.Result); } case State.AuthorizationEnd: { goto case State.ResourceBegin; }
我们看到,这里承接上面的步骤,实际执行了授权过滤器。接下来,是资源过滤器:
case State.ResourceBegin: { _cursor.Reset(); goto case State.ResourceNext; } case State.ResourceNext: { var current = _cursor.GetNextFilter<IResourceFilter, IAsyncResourceFilter>(); if (current.FilterAsync != null) { if (_resourceExecutingContext == null) { _resourceExecutingContext = new ResourceExecutingContext( _actionContext, _filters, _valueProviderFactories); } state = current.FilterAsync; goto case State.ResourceAsyncBegin; } else if (current.Filter != null) { if (_resourceExecutingContext == null) { _resourceExecutingContext = new ResourceExecutingContext( _actionContext, _filters, _valueProviderFactories); } state = current.Filter; goto case State.ResourceSyncBegin; } else { // All resource filters are currently on the stack - now execute the 'inside'. goto case State.ResourceInside; } } case State.ResourceAsyncBegin: { Debug.Assert(state != null); Debug.Assert(_resourceExecutingContext != null); var filter = (IAsyncResourceFilter)state; var resourceExecutingContext = _resourceExecutingContext; _diagnosticSource.BeforeOnResourceExecution(resourceExecutingContext, filter); var task = filter.OnResourceExecutionAsync(resourceExecutingContext, InvokeNextResourceFilterAwaitedAsync); if (task.Status != TaskStatus.RanToCompletion) { next = State.ResourceAsyncEnd; return task; } goto case State.ResourceAsyncEnd; } case State.ResourceAsyncEnd: { Debug.Assert(state != null); Debug.Assert(_resourceExecutingContext != null); var filter = (IAsyncResourceFilter)state; if (_resourceExecutedContext == null) { // If we get here then the filter didn't call 'next' indicating a short circuit. _resourceExecutedContext = new ResourceExecutedContext(_resourceExecutingContext, _filters) { Canceled = true, Result = _resourceExecutingContext.Result, }; _diagnosticSource.AfterOnResourceExecution(_resourceExecutedContext, filter); // A filter could complete a Task without setting a result if (_resourceExecutingContext.Result != null) { goto case State.ResourceShortCircuit; } } goto case State.ResourceEnd; } case State.ResourceSyncBegin: { Debug.Assert(state != null); Debug.Assert(_resourceExecutingContext != null); var filter = (IResourceFilter)state; var resourceExecutingContext = _resourceExecutingContext; _diagnosticSource.BeforeOnResourceExecuting(resourceExecutingContext, filter); filter.OnResourceExecuting(resourceExecutingContext); _diagnosticSource.AfterOnResourceExecuting(resourceExecutingContext, filter); if (resourceExecutingContext.Result != null) { _resourceExecutedContext = new ResourceExecutedContext(resourceExecutingContext, _filters) { Canceled = true, Result = _resourceExecutingContext.Result, }; goto case State.ResourceShortCircuit; } var task = InvokeNextResourceFilter(); if (task.Status != TaskStatus.RanToCompletion) { next = State.ResourceSyncEnd; return task; } goto case State.ResourceSyncEnd; } case State.ResourceSyncEnd: { Debug.Assert(state != null); Debug.Assert(_resourceExecutingContext != null); Debug.Assert(_resourceExecutedContext != null); var filter = (IResourceFilter)state; var resourceExecutedContext = _resourceExecutedContext; _diagnosticSource.BeforeOnResourceExecuted(resourceExecutedContext, filter); filter.OnResourceExecuted(resourceExecutedContext); _diagnosticSource.AfterOnResourceExecuted(resourceExecutedContext, filter); goto case State.ResourceEnd; } case State.ResourceShortCircuit: { Debug.Assert(state != null); Debug.Assert(_resourceExecutingContext != null); Debug.Assert(_resourceExecutedContext != null); _logger.ResourceFilterShortCircuited((IFilterMetadata)state); var task = InvokeResultAsync(_resourceExecutingContext.Result); if (task.Status != TaskStatus.RanToCompletion) { next = State.ResourceEnd; return task; } goto case State.ResourceEnd; } case State.ResourceInside: { goto case State.ExceptionBegin; }
可以看到,整个流程和授权过滤器的流程非常相似。接下来是异常过滤器:
case State.ExceptionBegin: { _cursor.Reset(); goto case State.ExceptionNext; } case State.ExceptionNext: { var current = _cursor.GetNextFilter<IExceptionFilter, IAsyncExceptionFilter>(); if (current.FilterAsync != null) { state = current.FilterAsync; goto case State.ExceptionAsyncBegin; } else if (current.Filter != null) { state = current.Filter; goto case State.ExceptionSyncBegin; } else if (scope == Scope.Exception) { // All exception filters are on the stack already - so execute the 'inside'. goto case State.ExceptionInside; } else { // There are no exception filters - so jump right to the action. Debug.Assert(scope == Scope.Invoker || scope == Scope.Resource); goto case State.ActionBegin; } } case State.ExceptionAsyncBegin: { var task = InvokeNextExceptionFilterAsync(); if (task.Status != TaskStatus.RanToCompletion) { next = State.ExceptionAsyncResume; return task; } goto case State.ExceptionAsyncResume; } case State.ExceptionAsyncResume: { Debug.Assert(state != null); var filter = (IAsyncExceptionFilter)state; var exceptionContext = _exceptionContext; // When we get here we're 'unwinding' the stack of exception filters. If we have an unhandled exception, // we'll call the filter. Otherwise there's nothing to do. if (exceptionContext?.Exception != null && !exceptionContext.ExceptionHandled) { _diagnosticSource.BeforeOnExceptionAsync(exceptionContext, filter); var task = filter.OnExceptionAsync(exceptionContext); if (task.Status != TaskStatus.RanToCompletion) { next = State.ExceptionAsyncEnd; return task; } goto case State.ExceptionAsyncEnd; } goto case State.ExceptionEnd; } case State.ExceptionAsyncEnd: { Debug.Assert(state != null); Debug.Assert(_exceptionContext != null); var filter = (IAsyncExceptionFilter)state; var exceptionContext = _exceptionContext; _diagnosticSource.AfterOnExceptionAsync(exceptionContext, filter); if (exceptionContext.Exception == null || exceptionContext.ExceptionHandled) { // We don't need to do anthing to trigger a short circuit. If there's another // exception filter on the stack it will check the same set of conditions // and then just skip itself. _logger.ExceptionFilterShortCircuited(filter); } goto case State.ExceptionEnd; } case State.ExceptionSyncBegin: { var task = InvokeNextExceptionFilterAsync(); if (task.Status != TaskStatus.RanToCompletion) { next = State.ExceptionSyncEnd; return task; } goto case State.ExceptionSyncEnd; } case State.ExceptionSyncEnd: { Debug.Assert(state != null); var filter = (IExceptionFilter)state; var exceptionContext = _exceptionContext; // When we get here we're 'unwinding' the stack of exception filters. If we have an unhandled exception, // we'll call the filter. Otherwise there's nothing to do. if (exceptionContext?.Exception != null && !exceptionContext.ExceptionHandled) { _diagnosticSource.BeforeOnException(exceptionContext, filter); filter.OnException(exceptionContext); _diagnosticSource.AfterOnException(exceptionContext, filter); if (exceptionContext.Exception == null || exceptionContext.ExceptionHandled) { // We don't need to do anthing to trigger a short circuit. If there's another // exception filter on the stack it will check the same set of conditions // and then just skip itself. _logger.ExceptionFilterShortCircuited(filter); } } goto case State.ExceptionEnd; } case State.ExceptionInside: { goto case State.ActionBegin; } case State.ExceptionHandled: { // We arrive in this state when an exception happened, but was handled by exception filters // either by setting ExceptionHandled, or nulling out the Exception or setting a result // on the ExceptionContext. // // We need to execute the result (if any) and then exit gracefully which unwinding Resource // filters. Debug.Assert(state != null); Debug.Assert(_exceptionContext != null); if (_exceptionContext.Result == null) { _exceptionContext.Result = new EmptyResult(); } if (scope == Scope.Resource) { Debug.Assert(_exceptionContext.Result != null); _result = _exceptionContext.Result; } var task = InvokeResultAsync(_exceptionContext.Result); if (task.Status != TaskStatus.RanToCompletion) { next = State.ResourceInsideEnd; return task; } goto case State.ResourceInsideEnd; } case State.ExceptionEnd: { var exceptionContext = _exceptionContext; if (scope == Scope.Exception) { isCompleted = true; return Task.CompletedTask; } if (exceptionContext != null) { if (exceptionContext.Result != null || exceptionContext.Exception == null || exceptionContext.ExceptionHandled) { goto case State.ExceptionHandled; } Rethrow(exceptionContext); Debug.Fail("unreachable"); } goto case State.ResultBegin; }
接下来是动作过滤器:
case State.ActionBegin: { var task = InvokeInnerFilterAsync(); if (task.Status != TaskStatus.RanToCompletion) { next = State.ActionEnd; return task; } goto case State.ActionEnd; } case State.ActionEnd: { if (scope == Scope.Exception) { // If we're inside an exception filter, let's allow those filters to 'unwind' before // the result. isCompleted = true; return Task.CompletedTask; } Debug.Assert(scope == Scope.Invoker || scope == Scope.Resource); goto case State.ResultBegin; }
然后是结果过滤器:
case State.ResultBegin: { _cursor.Reset(); goto case State.ResultNext; } case State.ResultNext: { var current = _cursor.GetNextFilter<IResultFilter, IAsyncResultFilter>(); if (current.FilterAsync != null) { if (_resultExecutingContext == null) { _resultExecutingContext = new ResultExecutingContext(_actionContext, _filters, _result, _instance); } state = current.FilterAsync; goto case State.ResultAsyncBegin; } else if (current.Filter != null) { if (_resultExecutingContext == null) { _resultExecutingContext = new ResultExecutingContext(_actionContext, _filters, _result, _instance); } state = current.Filter; goto case State.ResultSyncBegin; } else { goto case State.ResultInside; } } case State.ResultAsyncBegin: { Debug.Assert(state != null); Debug.Assert(_resultExecutingContext != null); var filter = (IAsyncResultFilter)state; var resultExecutingContext = _resultExecutingContext; _diagnosticSource.BeforeOnResultExecution(resultExecutingContext, filter); var task = filter.OnResultExecutionAsync(resultExecutingContext, InvokeNextResultFilterAwaitedAsync); if (task.Status != TaskStatus.RanToCompletion) { next = State.ResultAsyncEnd; return task; } goto case State.ResultAsyncEnd; } case State.ResultAsyncEnd: { Debug.Assert(state != null); Debug.Assert(_resultExecutingContext != null); var filter = (IAsyncResultFilter)state; var resultExecutingContext = _resultExecutingContext; var resultExecutedContext = _resultExecutedContext; if (resultExecutedContext == null || resultExecutingContext.Cancel) { // Short-circuited by not calling next || Short-circuited by setting Cancel == true _logger.ResultFilterShortCircuited(filter); _resultExecutedContext = new ResultExecutedContext( _actionContext, _filters, resultExecutingContext.Result, _instance) { Canceled = true, }; } _diagnosticSource.AfterOnResultExecution(_resultExecutedContext, filter); goto case State.ResultEnd; } case State.ResultSyncBegin: { Debug.Assert(state != null); Debug.Assert(_resultExecutingContext != null); var filter = (IResultFilter)state; var resultExecutingContext = _resultExecutingContext; _diagnosticSource.BeforeOnResultExecuting(resultExecutingContext, filter); filter.OnResultExecuting(resultExecutingContext); _diagnosticSource.AfterOnResultExecuting(resultExecutingContext, filter); if (_resultExecutingContext.Cancel) { // Short-circuited by setting Cancel == true _logger.ResultFilterShortCircuited(filter); _resultExecutedContext = new ResultExecutedContext( resultExecutingContext, _filters, resultExecutingContext.Result, _instance) { Canceled = true, }; goto case State.ResultEnd; } var task = InvokeNextResultFilterAsync(); if (task.Status != TaskStatus.RanToCompletion) { next = State.ResultSyncEnd; return task; } goto case State.ResultSyncEnd; } case State.ResultSyncEnd: { Debug.Assert(state != null); Debug.Assert(_resultExecutingContext != null); Debug.Assert(_resultExecutedContext != null); var filter = (IResultFilter)state; var resultExecutedContext = _resultExecutedContext; _diagnosticSource.BeforeOnResultExecuted(resultExecutedContext, filter); filter.OnResultExecuted(resultExecutedContext); _diagnosticSource.AfterOnResultExecuted(resultExecutedContext, filter); goto case State.ResultEnd; }
接下来,我们需要重点关注IActionResult如何执行的:
case State.ResultInside: { // If we executed result filters then we need to grab the result from there. if (_resultExecutingContext != null) { _result = _resultExecutingContext.Result; } if (_result == null) { // The empty result is always flowed back as the 'executed' result if we don't have one. _result = new EmptyResult(); } //执行结果,关键步骤 var task = InvokeResultAsync(_result); if (task.Status != TaskStatus.RanToCompletion) { next = State.ResultEnd; return task; } goto case State.ResultEnd; } case State.ResultEnd: { var result = _result; if (scope == Scope.Result) { if (_resultExecutedContext == null) { _resultExecutedContext = new ResultExecutedContext(_actionContext, _filters, result, _instance); } isCompleted = true; return Task.CompletedTask; } Rethrow(_resultExecutedContext); goto case State.ResourceInsideEnd; }
我们来看看这个InvokeResultAsync方法,实质上就是调用了IActionResult的ExecuteResultAsync方法。
protected async Task InvokeResultAsync(IActionResult result) { var actionContext = _actionContext; _diagnosticSource.BeforeActionResult(actionContext, result); try { //这里的步骤 await result.ExecuteResultAsync(actionContext); } finally { _diagnosticSource.AfterActionResult(actionContext, result); } }
这就是ResourceInvokier的主要内容。还有一点重要的是几个抽象方法,它们会在ControllerActionInvoker中实现。
protected abstract void ReleaseResources(); protected abstract Task InvokeInnerFilterAsync();