zoukankan      html  css  js  c++  java
  • ASP.NET Core学习总结(3)

      我们重点来看看这个InvokeInnerFilterAsync。

     protected override async Task InvokeInnerFilterAsync()
            {
                var next = State.ActionBegin;
                var scope = Scope.Invoker;
                var state = (object)null;
                var isCompleted = false;
    
                while (!isCompleted)
                {
                    await Next(ref next, ref scope, ref state, ref isCompleted);
                }
            }

      似曾相识,它与ResourceInvoker的InvokeFilterPipelineAsync几乎是一模一样的。并且也有一个Next方法,里面也是一个大的switch语句,然后是很多case。

     case State.ActionBegin:
                        {
                            var controllerContext = _controllerContext;
    
                            _cursor.Reset();
    
                            _instance = _cacheEntry.ControllerFactory(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 ActionExecutingContext(_controllerContext, _filters, _arguments, _instance);
                                }
    
                                state = current.FilterAsync;
                                goto case State.ActionAsyncBegin;
                            }
                            else if (current.Filter != null)
                            {
                                if (_actionExecutingContext == null)
                                {
                                    _actionExecutingContext = new ActionExecutingContext(_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;
    
                            _diagnosticSource.BeforeOnActionExecution(actionExecutingContext, 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 ActionExecutedContext(
                                    _controllerContext,
                                    _filters,
                                    _instance)
                                {
                                    Canceled = true,
                                    Result = _actionExecutingContext.Result,
                                };
                            }
    
                            _diagnosticSource.AfterOnActionExecution(_actionExecutedContext, filter);
    
                            goto case State.ActionEnd;
                        }
    
                    case State.ActionSyncBegin:
                        {
                            Debug.Assert(state != null);
                            Debug.Assert(_actionExecutingContext != null);
    
                            var filter = (IActionFilter)state;
                            var actionExecutingContext = _actionExecutingContext;
    
                            _diagnosticSource.BeforeOnActionExecuting(actionExecutingContext, filter);
    
                            filter.OnActionExecuting(actionExecutingContext);
    
                            _diagnosticSource.AfterOnActionExecuting(actionExecutingContext, filter);
    
                            if (actionExecutingContext.Result != null)
                            {
                                // Short-circuited by setting a result.
                                _logger.ActionFilterShortCircuited(filter);
    
                                _actionExecutedContext = new ActionExecutedContext(
                                    _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;
    
                            _diagnosticSource.BeforeOnActionExecuted(actionExecutedContext, filter);
    
                            filter.OnActionExecuted(actionExecutedContext);
    
                            _diagnosticSource.AfterOnActionExecuted(actionExecutedContext, filter);
    
                            goto case State.ActionEnd;
                        }

      如果我们查看之前的部分,就会发现。在ResourceInvoker中的动作过滤器部分并没有真正的执行,而是调用了抽象方法InvokeInnerFilterAsync。

        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;
                            }

      也就是说,所有的ActionFilter终归到底是在ControlerActionInvoker中执行的。接着我们来看Next方法的后面部分。

     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 ActionExecutedContext(_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();

      关键应该是那个InvokeActionMethodAsync方法。

     private async Task InvokeActionMethodAsync()
            {
                var controllerContext = _controllerContext;
                var executor = _cacheEntry.ActionMethodExecutor;
                var controller = _instance;
                var arguments = _arguments;
                var orderedArguments = PrepareArguments(arguments, executor);
    
                var diagnosticSource = _diagnosticSource;
                var logger = _logger;
    
                IActionResult result = null;
                try
                {
                    diagnosticSource.BeforeActionMethod(
                        controllerContext,
                        arguments,
                        controller);
                    logger.ActionMethodExecuting(controllerContext, orderedArguments);
    
                      //关键从这开始
                    var returnType = executor.MethodReturnType;
                    if (returnType == typeof(void))
                    {
                        // Sync method returning void
                        executor.Execute(controller, orderedArguments);
                        result = new EmptyResult();
                    }
                    else if (returnType == typeof(Task))
                    {
                        // Async method returning Task
                        // Avoid extra allocations by calling Execute rather than ExecuteAsync and casting to Task.
                        await (Task)executor.Execute(controller, orderedArguments);
                        result = new EmptyResult();
                    }
                    else if (returnType == typeof(Task<IActionResult>))
                    {
                        // Async method returning Task<IActionResult>
                        // Avoid extra allocations by calling Execute rather than ExecuteAsync and casting to Task<IActionResult>.
                        result = await (Task<IActionResult>)executor.Execute(controller, orderedArguments);
                        if (result == null)
                        {
                            throw new InvalidOperationException(
                                Resources.FormatActionResult_ActionReturnValueCannotBeNull(typeof(IActionResult)));
                        }
                    }
                    else if (IsResultIActionResult(executor))
                    {
                        if (executor.IsMethodAsync)
                        {
                            // Async method returning awaitable-of-IActionResult (e.g., Task<ViewResult>)
                            // We have to use ExecuteAsync because we don't know the awaitable's type at compile time.
                            result = (IActionResult)await executor.ExecuteAsync(controller, orderedArguments);
                        }
                        else
                        {
                            // Sync method returning IActionResult (e.g., ViewResult)
                            result = (IActionResult)executor.Execute(controller, orderedArguments);
                        }
    
                        if (result == null)
                        {
                            throw new InvalidOperationException(
                                Resources.FormatActionResult_ActionReturnValueCannotBeNull(executor.AsyncResultType ?? returnType));
                        }
                    }
                    else if (!executor.IsMethodAsync)
                    {
                        // Sync method returning arbitrary object
                        var resultAsObject = executor.Execute(controller, orderedArguments);
                        result = resultAsObject as IActionResult ?? new ObjectResult(resultAsObject)
                        {
                            DeclaredType = returnType,
                        };
                    }
                    else if (executor.AsyncResultType == typeof(void))
                    {
                        // Async method returning awaitable-of-void
                        await executor.ExecuteAsync(controller, orderedArguments);
                        result = new EmptyResult();
                    }
                    else
                    {
                        // Async method returning awaitable-of-nonvoid
                        var resultAsObject = await executor.ExecuteAsync(controller, orderedArguments);
                        result = resultAsObject as IActionResult ?? new ObjectResult(resultAsObject)
                        {
                            DeclaredType = executor.AsyncResultType,
                        };
                    }
    
                    _result = result;
                    logger.ActionMethodExecuted(controllerContext, result);
                }
                finally
                {
                    diagnosticSource.AfterActionMethod(
                        controllerContext,
                        arguments,
                        controllerContext,
                        result);
                }
            }

      上面的方法在于不断判断returnType的类型,根据不同的类型执行不同的操作。不难发现,这些returnType正是我们所写的Action的返回类型。换句话说,executor.Execute执行的正是我们的Action方法。那么,executor又是什么呢?它是一个ObjectMethodExecutor类型的变量。从它构造函数可以看出,它实质上是对一个方法的包装。

    private ObjectMethodExecutor(MethodInfo methodInfo, TypeInfo targetTypeInfo, object[] parameterDefaultValues)
            {
                if (methodInfo == null)
                {
                    throw new ArgumentNullException(nameof(methodInfo));
                }
    
                MethodInfo = methodInfo;
                MethodParameters = methodInfo.GetParameters();
                TargetTypeInfo = targetTypeInfo;
                MethodReturnType = methodInfo.ReturnType;
    
                var isAwaitable = CoercedAwaitableInfo.IsTypeAwaitable(MethodReturnType, out var coercedAwaitableInfo);
    
                IsMethodAsync = isAwaitable;
                AsyncResultType = isAwaitable ? coercedAwaitableInfo.AwaitableInfo.ResultType : null;
    
                // Upstream code may prefer to use the sync-executor even for async methods, because if it knows
                // that the result is a specific Task<T> where T is known, then it can directly cast to that type
                // and await it without the extra heap allocations involved in the _executorAsync code path.
                  //看这里
                _executor = GetExecutor(methodInfo, targetTypeInfo);
    
                if (IsMethodAsync)
                {
                    _executorAsync = GetExecutorAsync(methodInfo, targetTypeInfo, coercedAwaitableInfo);
                }
    
                _parameterDefaultValues = parameterDefaultValues;
            }
    public object Execute(object target, object[] parameters)
            {
                return _executor(target, parameters);
            }

      Execute方法也只是委托_executor去执行了。而_executor又是在构造函数中赋值的,下面是GetExecutor方法。

    private static MethodExecutor GetExecutor(MethodInfo methodInfo, TypeInfo targetTypeInfo)
            {
                // Parameters to executor
                var targetParameter = Expression.Parameter(typeof(object), "target");
                var parametersParameter = Expression.Parameter(typeof(object[]), "parameters");
    
                // Build parameter list
                var parameters = new List<Expression>();
                var paramInfos = methodInfo.GetParameters();
                for (int i = 0; i < paramInfos.Length; i++)
                {
                    var paramInfo = paramInfos[i];
                    var valueObj = Expression.ArrayIndex(parametersParameter, Expression.Constant(i));
                    var valueCast = Expression.Convert(valueObj, paramInfo.ParameterType);
    
                    // valueCast is "(Ti) parameters[i]"
                    parameters.Add(valueCast);
                }
    
                // Call method
                var instanceCast = Expression.Convert(targetParameter, targetTypeInfo.AsType());
                var methodCall = Expression.Call(instanceCast, methodInfo, parameters);
    
                // methodCall is "((Ttarget) target) method((T0) parameters[0], (T1) parameters[1], ...)"
                // Create function
                if (methodCall.Type == typeof(void))
                {
                    var lambda = Expression.Lambda<VoidMethodExecutor>(methodCall, targetParameter, parametersParameter);
                    var voidExecutor = lambda.Compile();
                    return WrapVoidMethod(voidExecutor);
                }
                else
                {
                    // must coerce methodCall to match ActionExecutor signature
                    var castMethodCall = Expression.Convert(methodCall, typeof(object));
                    var lambda = Expression.Lambda<MethodExecutor>(castMethodCall, targetParameter, parametersParameter);
                    return lambda.Compile();
                }
            }

      可以看到,上面利用表达式类编译成了委托,并且区分有无返回值的情况。至此,我们已经过了整个MVC框架的流程。现在,让我们再重新梳理一遍。

    ​   Internet=>Application=>Middleware=>IRourer=>MvcRouterHandler=>ControllerActionInvoker=》ActionFilter

    ​   网络和应用程序之间,通过HTTP协议交互信息。而在应用程序内部,又有由一系列中间件编译成的委托链。然后是整个MVC的入口点,即路由中间件。其中使用了IRouter的RouteAsync方法匹配路由。而在IRouter的默认实现MvcRouterHandler中又调用了IActionInvoker的InvokeAsync方法。IActionInvoker的默认实现ControllerActionInvoker又继承了ResourceInvoker。在ResourceInvoker中,执行了整个过滤器管道的流程。而动作过滤器和真正的动作方法则是在ControllerActionInvoker中执行的。

  • 相关阅读:
    Vijos / 题库 / 输油管道问题
    军事机密(Secret.pas)
    1164 统计数字
    1142 奖学金 sort做法
    1487 大批整数排序
    1487 大批整数排序
    1545 最简单排序
    1470 数列处理
    1683 车厢重组
    spin.js无图片实现loading进度条,支持但非依赖jquery
  • 原文地址:https://www.cnblogs.com/xsddxz/p/9059736.html
Copyright © 2011-2022 走看看