二、内部处理机制解析
1.总体流程
通过下图 来看一下总体的流程:
图1
这涉及三部分内容:
第一部分,在invoker的生成阶段。在第14章讲invoker的生成的时候,讲到了Action的执行者的获取,它是从一系列系统定义的XXXResultExecutor中筛选出来的,虽然它们名为XXXResultExecutor,但它们都是Action的执行者而不是ActionResult的执行者,都是ActionMethodExecutor的子类。以Action是同步还是异步以及Action的返回值类型为筛选条件,具体这部分内容见图 14‑2所示XXXResultExecutor列表及其后面的筛选逻辑部分。在图 17‑1中,筛选出了被请求的Action对应的XXXResultExecutor,若以Home/Index这个默认的Action为例,这个XXXResultExecutor应该是SyncActionResultExecutor。
第二部分,在Action Filters的处理阶段。这部分内容见16.5 Filter的执行,此处恰好以Action Filter为例讲了Action Filter的执行方式及Action被执行的过程。在这个阶段,会调用上文筛选出的SyncActionResultExecutor的Execute方法来执行Home/Index这个 Action。执行结果返回一个IActionResult。
第三部分,在Result Filters的处理阶段。这个阶段和Action Filters的逻辑相似,只不过前者的核心是Action的执行,后者的核心是Action的执行结果的执行。二者都分为OnExecuting和OnExecuted两个方法,这两个方法也都在其对应的核心执行方法前后执行。
整体流程是这样,下面看一下细节。
2. ActionMethodExecutor的选择与执行
第一部分,系统为什么要定义这么多种XXXResultExecutor并且在请求的时候一个个筛选合适的XXXResultExecutor呢?从筛选规则是以Action的同步、异步以及Action的返回值类型来看,这么多种XXXResultExecutor就是为了处理不同的Action类型。
依然以Home/Index为例,在筛选XXXResultExecutor的时候,最终返回结果是SyncActionResultExecutor。它的代码如下:
private class SyncActionResultExecutor : ActionMethodExecutor { public override ValueTask<IActionResult> Execute( IActionResultTypeMapper mapper, ObjectMethodExecutor executor, object controller, object[] arguments) { var actionResult = (IActionResult)executor.Execute(controller, arguments); EnsureActionResultNotNull(executor, actionResult); return new ValueTask<IActionResult>(actionResult); } protected override bool CanExecute(ObjectMethodExecutor executor) => !executor.IsMethodAsync && typeof(IActionResult).IsAssignableFrom(executor.MethodReturnType); }
XXXResultExecutor的CanExecute方法是筛选的条件,通过这个方法判断它是否适合当前请求的目标Action。它要求这个Action不是异步的并且返回结果类型是派生自IActionResult的。而Home/Index这个Action标识的返回结果是IActionResult,实际是通过View()这个方法返回的,这个方法的返回结果类型实际是IActionResult的派生类ViewResult。这样的派生类还有常见的JsonResult和ContentResult等,他们都继承了ActionResult,而ActionResult实现了IActionResult接口。所以如果一个Action是同步的并且返回结果是JsonResult或ContentResult的时候,对应的XXXResultExecutor也是SyncActionResultExecutor。
第二部分中,Action的执行是在XXXResultExecutor的Execute方法,它会进一步调用了ObjectMethodExecutor的Execute方法。实际上所有的Action的都是由ObjectMethodExecutor的Execute方法来执行执行的。而众多的XXXResultExecutor方法的作用是调用这个方法并且对返回结果进行验证和处理。例如SyncActionResultExecutor会通过EnsureActionResultNotNull方法确保返回的结果不能为空。
如果是sting类型呢?它对应的是SyncObjectResultExecutor,代码如下:
private class SyncObjectResultExecutor : ActionMethodExecutor { public override ValueTask<IActionResult> Execute( IActionResultTypeMapper mapper, ObjectMethodExecutor executor, object controller, object[] arguments) { // Sync method returning arbitrary object var returnValue = executor.Execute(controller, arguments); var actionResult = ConvertToActionResult(mapper, returnValue, executor.MethodReturnType); return new ValueTask<IActionResult>(actionResult); } // Catch-all for sync methods protected override bool CanExecute(ObjectMethodExecutor executor) => !executor.IsMethodAsync; }
由于string不是IActionResult的子类,所以会通过ConvertToActionResult方法对返回结果returnValue进行处理。
private IActionResult ConvertToActionResult(IActionResultTypeMapper mapper, object returnValue, Type declaredType) { var result = (returnValue as IActionResult) ?? mapper.Convert(returnValue, declaredType); if (result == null) { throw new InvalidOperationException(Resources.FormatActionResult_ActionReturnValueCannotBeNull(declaredType)); } return result; }
如果returnValue是IActionResult的子类,则返回returnValue,否则调用一个Convert方法将returnValue转换一下:
public IActionResult Convert(object value, Type returnType) { if (returnType == null) { throw new ArgumentNullException(nameof(returnType)); } if (value is IConvertToActionResult converter) { return converter.Convert(); } return new ObjectResult(value) { DeclaredType = returnType, }; }
这个方法会判断returnValue是否实现了IConvertToActionResult接口,如果是则调用该接口的Convert方法转换成IActionResult类型,否则会将returnValue封装成ObjectResult。ObjectResult也是ActionResult的子类。下文有个ActionResult<T> 类型就是这样,该例会介绍。
所以,针对不同类型的Action,系统设置了多种XXXResultExecutor来处理,最终结果无论是什么,都会被转换成IActionResult类型。方便在图 17‑1所示的第三部分进行IActionResult的执行。