ASP.NET Core MVC — MVC执行概貌(1) IActionInvoker的构建

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

最后,当所有这些都处理完成之后,返回ActionInvokerProviderContextResult属性。

这里的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中的ControllerActionInvokerRazorPage中的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实例。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值