private Task InvokeNextActionFilterAsync() { try { var next = State.ActionNext; var state = (object)null; var scope = Scope.Action; var isCompleted = false; while (!isCompleted) { var lastTask = Next(ref next, ref scope, ref state, ref isCompleted); if (!lastTask.IsCompletedSuccessfully) { return(Awaited(this, lastTask, next, scope, state, isCompleted)); } } } catch (Exception exception) { _actionExecutedContext = new ActionExecutedContextSealed(_controllerContext, _filters, _instance) { ExceptionDispatchInfo = ExceptionDispatchInfo.Capture(exception), }; } Debug.Assert(_actionExecutedContext != null); return(Task.CompletedTask);
private Task Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted) { switch (next) { case State.ActionBegin: { var controllerContext = _controllerContext; _cursor.Reset(); _logger.ExecutingControllerFactory(controllerContext); _instance = _cacheEntry.ControllerFactory(controllerContext); _logger.ExecutedControllerFactory(controllerContext); _arguments = new Dictionary <string, object>(StringComparer.OrdinalIgnoreCase); var task = BindArgumentsAsync(); if (task.Status != TaskStatus.RanToCompletion) { next = State.ActionNext; return(task); } goto case State.ActionNext; } case State.ActionNext: { var current = _cursor.GetNextFilter <IActionFilter, IAsyncActionFilter>(); if (current.FilterAsync != null) { if (_actionExecutingContext == null) { _actionExecutingContext = new ActionExecutingContextSealed(_controllerContext, _filters, _arguments, _instance); } state = current.FilterAsync; goto case State.ActionAsyncBegin; } else if (current.Filter != null) { if (_actionExecutingContext == null) { _actionExecutingContext = new ActionExecutingContextSealed(_controllerContext, _filters, _arguments, _instance); } state = current.Filter; goto case State.ActionSyncBegin; } else { goto case State.ActionInside; } } case State.ActionAsyncBegin: { Debug.Assert(state != null); Debug.Assert(_actionExecutingContext != null); var filter = (IAsyncActionFilter)state; var actionExecutingContext = _actionExecutingContext; _diagnosticListener.BeforeOnActionExecution(actionExecutingContext, filter); _logger.BeforeExecutingMethodOnFilter( MvcCoreLoggerExtensions.ActionFilter, nameof(IAsyncActionFilter.OnActionExecutionAsync), filter); var task = filter.OnActionExecutionAsync(actionExecutingContext, InvokeNextActionFilterAwaitedAsync); if (task.Status != TaskStatus.RanToCompletion) { next = State.ActionAsyncEnd; return(task); } goto case State.ActionAsyncEnd; } case State.ActionAsyncEnd: { Debug.Assert(state != null); Debug.Assert(_actionExecutingContext != null); var filter = (IAsyncActionFilter)state; if (_actionExecutedContext == null) { // If we get here then the filter didn't call 'next' indicating a short circuit. _logger.ActionFilterShortCircuited(filter); _actionExecutedContext = new ActionExecutedContextSealed( _controllerContext, _filters, _instance) { Canceled = true, Result = _actionExecutingContext.Result, }; } _diagnosticListener.AfterOnActionExecution(_actionExecutedContext, filter); _logger.AfterExecutingMethodOnFilter( MvcCoreLoggerExtensions.ActionFilter, nameof(IAsyncActionFilter.OnActionExecutionAsync), filter); goto case State.ActionEnd; } case State.ActionSyncBegin: { Debug.Assert(state != null); Debug.Assert(_actionExecutingContext != null); var filter = (IActionFilter)state; var actionExecutingContext = _actionExecutingContext; _diagnosticListener.BeforeOnActionExecuting(actionExecutingContext, filter); _logger.BeforeExecutingMethodOnFilter( MvcCoreLoggerExtensions.ActionFilter, nameof(IActionFilter.OnActionExecuting), filter); filter.OnActionExecuting(actionExecutingContext); _diagnosticListener.AfterOnActionExecuting(actionExecutingContext, filter); _logger.AfterExecutingMethodOnFilter( MvcCoreLoggerExtensions.ActionFilter, nameof(IActionFilter.OnActionExecuting), filter); if (actionExecutingContext.Result != null) { // Short-circuited by setting a result. _logger.ActionFilterShortCircuited(filter); _actionExecutedContext = new ActionExecutedContextSealed( _actionExecutingContext, _filters, _instance) { Canceled = true, Result = _actionExecutingContext.Result, }; goto case State.ActionEnd; } var task = InvokeNextActionFilterAsync(); if (task.Status != TaskStatus.RanToCompletion) { next = State.ActionSyncEnd; return(task); } goto case State.ActionSyncEnd; } case State.ActionSyncEnd: { Debug.Assert(state != null); Debug.Assert(_actionExecutingContext != null); Debug.Assert(_actionExecutedContext != null); var filter = (IActionFilter)state; var actionExecutedContext = _actionExecutedContext; _diagnosticListener.BeforeOnActionExecuted(actionExecutedContext, filter); _logger.BeforeExecutingMethodOnFilter( MvcCoreLoggerExtensions.ActionFilter, nameof(IActionFilter.OnActionExecuted), filter); filter.OnActionExecuted(actionExecutedContext); _diagnosticListener.AfterOnActionExecuted(actionExecutedContext, filter); _logger.AfterExecutingMethodOnFilter( MvcCoreLoggerExtensions.ActionFilter, nameof(IActionFilter.OnActionExecuted), filter); goto case State.ActionEnd; } case State.ActionInside: { var task = InvokeActionMethodAsync(); if (task.Status != TaskStatus.RanToCompletion) { next = State.ActionEnd; return(task); } goto case State.ActionEnd; } case State.ActionEnd: { if (scope == Scope.Action) { if (_actionExecutedContext == null) { _actionExecutedContext = new ActionExecutedContextSealed(_controllerContext, _filters, _instance) { Result = _result, }; } isCompleted = true; return(Task.CompletedTask); } var actionExecutedContext = _actionExecutedContext; Rethrow(actionExecutedContext); if (actionExecutedContext != null) { _result = actionExecutedContext.Result; } isCompleted = true; return(Task.CompletedTask); } default: throw new InvalidOperationException(); } }