ASP.NET Core学习总结
Posted xsddxz
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ASP.NET Core学习总结相关的知识,希望对你有一定的参考价值。
我们重点来看看这个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); }
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(); } }
? Internet=>Application=>Middleware=>IRourer=>MvcRouterHandler=>ControllerActionInvoker=》ActionFilter
? 网络和应用程序之间,通过HTTP协议交互信息。而在应用程序内部,又有由一系列中间件编译成的委托链。然后是整个MVC的入口点,即路由中间件。其中使用了IRouter的RouteAsync方法匹配路由。而在IRouter的默认实现MvcRouterHandler中又调用了IActionInvoker的InvokeAsync方法。IActionInvoker的默认实现ControllerActionInvoker又继承了ResourceInvoker。在ResourceInvoker中,执行了整个过滤器管道的流程。而动作过滤器和真正的动作方法则是在ControllerActionInvoker中执行的。
以上是关于ASP.NET Core学习总结的主要内容,如果未能解决你的问题,请参考以下文章
学习ASP.NET Core,怎能不了解请求处理管道[2]: 服务器在管道中的“龙头”地位
Asp.Net Core 轻松学-经常使用异步的你,可能需要看看这个文章