zoukankan      html  css  js  c++  java
  • .NET Core开发日志——Controller

    在理清路由的工作流程后,接下来需要考虑的,是MVC框架如何生成Controller以及它的生成时机。

    根据以前ASP.NET MVC的经验,Controller应该是由一个ControllerFactory构建的。查看ASP.NET Core MVC的源码,果然是有一个DefaultControllerFactory类,并且不出意外的,它拥有一个CreateController方法。

    public virtual object CreateController(ControllerContext context)
    {
        ...
    
        var controller = _controllerActivator.Create(context);
        foreach (var propertyActivator in _propertyActivators)
        {
            propertyActivator.Activate(context, controller);
        }
    
        return controller;
    }
    

    但细推其使用的场合,只出现在ControllerFactoryProvider的构造方法内部,且仅是用于判断所传入的controllerFactory类型是否是DefaultControllerFactory。

    public ControllerFactoryProvider(
        IControllerActivatorProvider activatorProvider,
        IControllerFactory controllerFactory,
        IEnumerable<IControllerPropertyActivator> propertyActivators)
    {
        ...
    
        _activatorProvider = activatorProvider;
    
        // Compat: Delegate to the IControllerFactory if it's not the default implementation.
        if (controllerFactory.GetType() != typeof(DefaultControllerFactory))
        {
            _factoryCreateController = controllerFactory.CreateController;
            _factoryReleaseController = controllerFactory.ReleaseController;
        }
    
        _propertyActivators = propertyActivators.ToArray();
    }
    

    再看ControllerFactoryProvider内部的CreateControllerFactory方法。这更像是一个真正创建Controller的工厂方法。

    public Func<ControllerContext, object> CreateControllerFactory(ControllerActionDescriptor descriptor)
    {
        ...
    
        if (_factoryCreateController != null)
        {
            return _factoryCreateController;
        }
    
        var controllerActivator = _activatorProvider.CreateActivator(descriptor);
        var propertyActivators = GetPropertiesToActivate(descriptor);
        object CreateController(ControllerContext controllerContext)
        {
            var controller = controllerActivator(controllerContext);
            for (var i = 0; i < propertyActivators.Length; i++)
            {
                var propertyActivator = propertyActivators[i];
                propertyActivator(controllerContext, controller);
            }
    
            return controller;
        }
    
        return CreateController;
    }
    

    创建方式分为两种,一种是使用自定义的工厂方法,另一种是通过ControllerActivatorProvider的CreateActivator方法。

    public Func<ControllerContext, object> CreateActivator(ControllerActionDescriptor descriptor)
    {
        ...
    
        var controllerType = descriptor.ControllerTypeInfo?.AsType();
        ...
    
        if (_controllerActivatorCreate != null)
        {
            return _controllerActivatorCreate;
        }
    
        var typeActivator = ActivatorUtilities.CreateFactory(controllerType, Type.EmptyTypes);
        return controllerContext => typeActivator(controllerContext.HttpContext.RequestServices, arguments: null);
    }
    

    明白了如何创建Controller,下面开始调查创建Controller的时机。

    ControllerFactoryProvider类的CreateControllerFactory方法是被ControllerActionInvokerCache类的GetCachedResult方法调用。

    public (ControllerActionInvokerCacheEntry cacheEntry, IFilterMetadata[] filters) GetCachedResult(ControllerContext controllerContext)
    {
        var cache = CurrentCache;
        var actionDescriptor = controllerContext.ActionDescriptor;
    
        IFilterMetadata[] filters;
        if (!cache.Entries.TryGetValue(actionDescriptor, out var cacheEntry))
        {
            var filterFactoryResult = FilterFactory.GetAllFilters(_filterProviders, controllerContext);
            filters = filterFactoryResult.Filters;
    
            var parameterDefaultValues = ParameterDefaultValues
                .GetParameterDefaultValues(actionDescriptor.MethodInfo);
    
            var objectMethodExecutor = ObjectMethodExecutor.Create(
                actionDescriptor.MethodInfo,
                actionDescriptor.ControllerTypeInfo,
                parameterDefaultValues);
    
            var controllerFactory = _controllerFactoryProvider.CreateControllerFactory(actionDescriptor);
            var controllerReleaser = _controllerFactoryProvider.CreateControllerReleaser(actionDescriptor);
            var propertyBinderFactory = ControllerBinderDelegateProvider.CreateBinderDelegate(
                _parameterBinder,
                _modelBinderFactory,
                _modelMetadataProvider,
                actionDescriptor);
    
            var actionMethodExecutor = ActionMethodExecutor.GetExecutor(objectMethodExecutor);
    
            cacheEntry = new ControllerActionInvokerCacheEntry(
                filterFactoryResult.CacheableFilters, 
                controllerFactory, 
                controllerReleaser,
                propertyBinderFactory,
                objectMethodExecutor,
                actionMethodExecutor);
            cacheEntry = cache.Entries.GetOrAdd(actionDescriptor, cacheEntry);
        }
        else
        {
            // Filter instances from statically defined filter descriptors + from filter providers
            filters = FilterFactory.CreateUncachedFilters(_filterProviders, controllerContext, cacheEntry.CachedFilters);
        }
    
        return (cacheEntry, filters);
    }
    

    其值作为ControllerActionInvokerCacheEntry对象的一部分被方法返回。

    GetCachedResult方法的上层调用者是ControllerActionInvokerProvider类的OnProvidersExecuting方法。

    public void OnProvidersExecuting(ActionInvokerProviderContext context)
    {
        ...
    
        if (context.ActionContext.ActionDescriptor is ControllerActionDescriptor)
        {
            var controllerContext = new ControllerContext(context.ActionContext);
            // PERF: These are rarely going to be changed, so let's go copy-on-write.
            controllerContext.ValueProviderFactories = new CopyOnWriteList<IValueProviderFactory>(_valueProviderFactories);
            controllerContext.ModelState.MaxAllowedErrors = _maxModelValidationErrors;
    
            var cacheResult = _controllerActionInvokerCache.GetCachedResult(controllerContext);
    
            var invoker = new ControllerActionInvoker(
                _logger,
                _diagnosticSource,
                controllerContext,
                cacheResult.cacheEntry,
                cacheResult.filters);
    
            context.Result = invoker;
        }
    }
    

    ControllerActionInvokerCacheEntry对象又被作为ControllerActionInvoker对象的一部分为ActionInvokerProviderContext的Result属性赋值。

    再往上跟踪,到了ActionInvokerFactory类的CreateInvoker方法。

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

    而它的调用者便是MvcRouteHandler或者MvcAttributeRouteHandler。

    public Task RouteAsync(RouteContext context)
    {
        ...
    
        context.Handler = (c) =>
        {
            var routeData = c.GetRouteData();
    
            var actionContext = new ActionContext(context.HttpContext, routeData, actionDescriptor);
            if (_actionContextAccessor != null)
            {
                _actionContextAccessor.ActionContext = actionContext;
            }
    
            var invoker = _actionInvokerFactory.CreateInvoker(actionContext);
            if (invoker == null)
            {
                throw new InvalidOperationException(
                    Resources.FormatActionInvokerFactory_CouldNotCreateInvoker(
                        actionDescriptor.DisplayName));
            }
    
            return invoker.InvokeAsync();
        };
    
        ...
    }
    

    到了这里创建Controller的工厂方法还没有被实际调用,此时Controller还是不存在的。所以还需要完成执行ControllerActionInvoker的InvokeAsync方法,或者更准确地说是其基类ResourceInvoker的InvokeAsync方法。

    public virtual async Task InvokeAsync()
    {
        try
        {
            ...
    
            using (_logger.ActionScope(_actionContext.ActionDescriptor))
            {
                ...
    
                try
                {
                    await InvokeFilterPipelineAsync();
                }
                ...
            }
        }
        ...
    }
    

    从InvokeFilterPipelineAsync方法开始,一系列的处理流程将依据不同状态逐步展开。

    private async Task InvokeFilterPipelineAsync()
    {
        var next = State.InvokeBegin;
    
        var scope = Scope.Invoker;
    
        var state = (object)null;
    
        var isCompleted = false;
    
        while (!isCompleted)
        {
            await Next(ref next, ref scope, ref state, ref isCompleted);
        }
    }
    

    而到了State.ActionBegin这一步(ControllerActionInvoker类的Next方法),终于能找到Controller工厂方法被执行的场合。

    private Task Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
    {
        switch (next)
        {
            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;
                }
            ...
            }            
        }
    }            
    

    最后以一张流程图总结上面的探寻过程。

  • 相关阅读:
    lr 增强窗格中,如何生成调试信息?
    lr 自带的例子,如何进行关联,通过代码的函数进行实现
    lr11 录制脚本时候,无法自动启动ie,查了网上很多方法都未解决?
    loadrunner11 录制脚步不成功,在录制概要出现“No Events were detected”,浮动窗口总是显示“0 Events”,解决办法
    loadrunner11 安装及破解教程来自百度文库
    安装loadrunner11 ,出现如下错误如何解决?
    回收站数据删除了,如何进行恢复?
    网管工作方面——————打印机删除了然后开机重启他依然存在,如何解决
    Windows 不能在 本地计算机 启动 SQL Server 服务 错误代码126
    Sorry, the page you are looking for is currently unavailable. Please try again later. Nginx
  • 原文地址:https://www.cnblogs.com/kenwoo/p/9496297.html
Copyright © 2011-2022 走看看