IActionInvoker
是通过IActionInvokerFactory
工厂构建的。
当构建IActionInvoker
时,IActionInvokerFactory
会遍历自身的IActionInvokerProvider
列表,依次调用provider.OnProvidersExecuting(context)
;然后再按逆序遍历该列表,依次调用provider.OnProvidersExecuted(context);
,从而形成如下的层级式调用:
provider0.OnProvidersExecuting(context);
provider1.OnProvidersExecuting(context);
provider2.OnProvidersExecuting(context);
...
...
...
...
provider2.OnProvidersExecuted(context);
provider1.OnProvidersExecuted(context);
provider0.OnProvidersExecuted(context);
最后,当所有这些都处理完成之后,返回ActionInvokerProviderContext
的Result
属性。
这里的ActionInvokerProviderContext
是一个非常简单的上下文变量,该类只包含了ActionContext
(输入)和IActionInvoker
(输出)两个属性:
public class ActionInvokerProviderContext
{
public ActionInvokerProviderContext(ActionContext actionContext)
{
if (actionContext == null) { /* throw */ }
ActionContext = actionContext;
}
public ActionContext ActionContext { get; }
public IActionInvoker Result { get; set; }
}
上文说到ActionInvokerFactory
会先以正序遍历自身的IActionInvokerProvider
,然后再反序遍历,其源码实现非常简单:
internal class ActionInvokerFactory : IActionInvokerFactory
{
private readonly IActionInvokerProvider[] _actionInvokerProviders;
public ActionInvokerFactory(IEnumerable<IActionInvokerProvider> actionInvokerProviders)
{
_actionInvokerProviders = actionInvokerProviders.OrderBy(item => item.Order).ToArray();
}
public IActionInvoker CreateInvoker(ActionContext actionContext)
{
var context = new ActionInvokerProviderContext(actionContext);
foreach (var provider in _actionInvokerProviders)
{
provider.OnProvidersExecuting(context);
}
for (var i = _actionInvokerProviders.Length - 1; i >= 0; i--)
{
_actionInvokerProviders[i].OnProvidersExecuted(context);
}
return context.Result;
}
}
IActionInvoker
可以有多种子类实现。比如,MVC
中的ControllerActionInvoker
和RazorPage
中的PageActionInvoker
是最常见的实现。
由于MVC
相交于RazorPage
有更广为人知,这个笔记系列以ControllerActionInvoker
为例,分析IActionInvoker
的构建与执行。
为了获取ControllerActionInvoker
实例,我们还需要ControllerActionInvokerProvider
,其核心代码是:
internal class ControllerActionInvokerProvider : IActionInvokerProvider
{
private readonly ControllerActionInvokerCache _controllerActionInvokerCache; // 注入
private readonly ILogger _logger; // 注入
private readonly DiagnosticListener _diagnosticListener; // 注入
private readonly IActionResultTypeMapper _mapper; // 注入
private readonly IActionContextAccessor _actionContextAccessor; // 注入
private readonly IReadOnlyList<IValueProviderFactory> _valueProviderFactories; // 注入MvcOptions 获取
private readonly int _maxModelValidationErrors; // 注入MvcOptions 获取
...
public void OnProvidersExecuting(ActionInvokerProviderContext context)
{
if (context == null) { /*throw*/ }
if (context.ActionContext.ActionDescriptor is ControllerActionDescriptor)
{
var controllerContext = new ControllerContext(context.ActionContext) {
ValueProviderFactories = new CopyOnWriteList<IValueProviderFactory>(_valueProviderFactories)
};
controllerContext.ModelState.MaxAllowedErrors = _maxModelValidationErrors;
var (cacheEntry, filters) = _controllerActionInvokerCache.GetCachedResult(controllerContext);
var invoker = new ControllerActionInvoker( _logger, _diagnosticListener, _actionContextAccessor, _mapper, controllerContext, cacheEntry, filters);
context.Result = invoker;
}
}
public void OnProvidersExecuted(ActionInvokerProviderContext context) { }
}
可以看到,ControllerActionInvoker
的过滤器都是优先从缓存中加载,然后简单地new
一个ControllerActinInvoker
实例。