我们重点来看看这个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 = ; 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中执行的。

ASP.NET Core学习总结(3)的更多相关文章

  1. ASP.NET Core学习系列

    .NET Core ASP.NET Core ASP.NET Core学习之一 入门简介 ASP.NET Core学习之二 菜鸟踩坑 ASP.NET Core学习之三 NLog日志 ASP.NET C ...

  2. WebAPI调用笔记 ASP.NET CORE 学习之自定义异常处理 MySQL数据库查询优化建议 .NET操作XML文件之泛型集合的序列化与反序列化 Asp.Net Core 轻松学-多线程之Task快速上手 Asp.Net Core 轻松学-多线程之Task(补充)

    WebAPI调用笔记   前言 即时通信项目中初次调用OA接口遇到了一些问题,因为本人从业后几乎一直做CS端项目,一个简单的WebAPI调用居然浪费了不少时间,特此记录. 接口描述 首先说明一下,基于 ...

  3. ASP.NET Core学习指导

    ASP.NET Core 学习指导 "工欲善其事必先利其器".我们在做事情之前,总应该做好充分的准备,熟悉自己的工具.就像玩游戏有一些最低配置一样,学习一个新的框架,也需要有一些基 ...

  4. Asp.Net Core学习笔记:入门篇

    Asp.Net Core 学习 基于.Net Core 2.2版本的学习笔记. 常识 像Django那样自动检查代码更新,自动重载服务器(太方便了) dotnet watch run 托管设置 设置项 ...

  5. ASP.NET Core学习零散记录

    赶着潮流听着歌,学着.net玩着Core 竹子学Core,目前主要看老A(http://www.cnblogs.com/artech/)和tom大叔的博客(http://www.cnblogs.com ...

  6. ASP.NET Core学习之三 NLog日志

    上一篇简单介绍了日志的使用方法,也仅仅是用来做下学习,更何况只能在console输出. NLog已是日志库的一员大佬,使用也简单方便,本文介绍的环境是居于.NET CORE 2.0 ,目前的版本也只有 ...

  7. ASP.NET Core学习之一 入门简介

    一.入门简介 在学习之前,要先了解ASP.NET Core是什么?为什么?很多人学习新技术功利心很重,恨不得立马就学会了. 其实,那样做很不好,马马虎虎,联系过程中又花费非常多的时间去解决所遇到的“问 ...

  8. ASP.NET Core学习总结(1)

    经过那么长时间的学习,终于想给自己这段时间的学习工作做个总结了.记得刚开始学习的时候,什么资料都没有,光就啃文档.不过,值得庆幸的是,自己总算还有一些Web开发的基础.至少ASP.NET的WebFor ...

  9. Asp.net Core学习笔记

    之前记在github上的,现在搬运过来 变化还是很大的,感觉和Nodejs有点类似,比如中间件的使用 ,努力学习ing... 优点 不依赖IIS 开源和跨平台 中间件支持 性能优化 无所不在的依赖注入 ...

  10. 2019年ASP.NET Core学习路线

    - [先决条件] + C# + Entity Framework + ASP.NET Core + SQL 基础知识 - [通用开发技能] + 学习 GIT, 在 GitHub 中创建开源项目 + 掌 ...

随机推荐

  1. MySQL 5.7 免安装版配置

      MySQL5.7免安装版配置 Mysql是一个比较流行且很好用的一款数据库软件,如下记录了我学习总结的mysql免安装版的配置经验. 一. 软件下载 5.7 32位https://dev.mysq ...

  2. eclipse Android 开发基础 Activity 窗体 界面

    eclipse Android 开发基础 新建工程 新建布局layout,new Android Activity就相当于窗体Form. 新建Activity自动生成src下同名的java代码. pu ...

  3. 带参数setTimeout

    /*         功能:修改 window.setTimeout,使之可以传递参数和对象参数         使用方法: window.setTimeout(回调函数,时间,参数1,,参数n)   ...

  4. linux vim操作技巧

    安装: NERDTree 从 http://www.vim.org/scripts/script.php?script_id=1658  下载 unzip NERD_tree.zip cd ~/.vi ...

  5. 在Eclipse中创建Maven版的Web工程

    步骤: 1.第一步 2.第二步 3.第三步 4.第四步 选中项目,右键在弹出的对话框中选择properties 5.第五步 6.第六步

  6. 查看linux中某个端口(port)是否被占用

    1.使用lsof lsof -i:端口号                     查看某个端口是否被占用 2.使用netstat 使用netstat -anp|grep 80

  7. Bind搭建DNS服务

    DNS域名解析服务(Domain Name System)是用于解析域名与IP地址对应关系的服务,功能上可以实现正向解析与反向解析: 正向解析:根据主机名(域名)查找对应的IP地址. 反向解析:根据I ...

  8. php防止会话固定攻击

    问题:希望确保应用不会受到会话固定攻击,即攻击者强制用户使用一个预定义的会话id. 解决方案:要求使用会话cookie但会话标识符不追加到URL,另外要频繁地生成新会话ID: <?php ini ...

  9. PHP 中 Traits 的简单使用

    PHP 5.4中的traits,是新引入的特性,中文还真不知道如何准确翻译好.其实际的目的,是为了有的场合想用多继承,但PHP又没多继承,于是就发明了这样的一个东西.       Traits可以理解 ...

  10. 一次清理Hbase的oldWALs的过程

    HBase版本:1.3.1 Hadoop版本:2.7.1 Zookeeper版本:3.4.6 --------------------------------- 检查线上业务系统的磁盘空间, 发现HD ...