• asp.net core mvc剖析:动作执行


    紧跟上一篇文章。通过路由和动作匹配后,最终会得到跟当前请求最匹配的一个ActionDescriptor,然后通过IActionInvoker执行动作。

    我们先来看一下IActionInvoker如何得到,代码如下:

    context.Handler = (c) =>
                {
                    var routeData = c.GetRouteData();
                    //根据actiondescriptor实例化ActionContext对象
                    var actionContext = new ActionContext(context.HttpContext, routeData, actionDescriptor);
                    if (_actionContextAccessor != null)
                    {
                        _actionContextAccessor.ActionContext = actionContext;
                    }
                    //创建IActionInvoker
                    var invoker = _actionInvokerFactory.CreateInvoker(actionContext);
                    if (invoker == null)
                    {
                        throw new InvalidOperationException(
                            Resources.FormatActionInvokerFactory_CouldNotCreateInvoker(
                                actionDescriptor.DisplayName));
                    }
                    //执行invoker处理请求
                    return invoker.InvokeAsync();
                };
    

      从上面的代码可以看到,一个IActionInvoker是通过IActionInvokerFactory创建,框架里该接口实现类是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;
            }
    

      在方法中,首先实例化一个ActionInvokerProviderContext,然后调用IActionInvokerProvider来设置context.Result,context.Result就是一个IActionInvoker,所以我们跟踪下框架中IActionInvokerProvider实现类,来看看它里面是如何工作的。框架中的提供了一个实现类ControllerActionInvokerProvider,在OnProvidersExecuting方法中创建了IActionInvoker对象,代码如下:

    public void OnProvidersExecuting(ActionInvokerProviderContext context)
            {
                if (context == null)
                {
                    throw new ArgumentNullException(nameof(context));
                }
    
                var actionDescriptor = context.ActionContext.ActionDescriptor as ControllerActionDescriptor;
    
                if (actionDescriptor != null)
                {
                    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 cacheState = _controllerActionInvokerCache.GetState(controllerContext);
    
                    context.Result = new ControllerActionInvoker(
                        _controllerFactory,
                        _argumentBinder,
                        _logger,
                        _diagnosticSource,
                        controllerContext,
                        cacheState.Filters,
                        cacheState.ActionMethodExecutor);
                }
            }
    

      从上面的代码我们可以看到,最终就是实例化了一个ControllerActionInvoker对象,该类构造方法前几个参数不再介绍了,重点是最后两个参数,一个是IFilterMetadata[],表示跟当前动作相关联的过滤器信息集合,一个是ObjectMethodExecutor,从名字上可以看出,这个就是控制器方法的执行器。而这两个参数来自cacheState,这个对象是通过调用_controllerActionInvokerCache.GetState(controllerContext)得到的,它是一个ControllerActionInvokerState结构体类型,定义如下:

     public struct ControllerActionInvokerState
            {
                public ControllerActionInvokerState(
                    IFilterMetadata[] filters,
                    ObjectMethodExecutor actionMethodExecutor)
                {
                    Filters = filters;
                    ActionMethodExecutor = actionMethodExecutor;
                }
                //动作过滤器集合
                public IFilterMetadata[] Filters { get; }
                //方法执行器
                public ObjectMethodExecutor ActionMethodExecutor { get; set; }
            }
    

      cacheState创建的过程如下:

     public ControllerActionInvokerState GetState(ControllerContext controllerContext)
            {
                var cache = CurrentCache;
                var actionDescriptor = controllerContext.ActionDescriptor;
    
                IFilterMetadata[] filters;
                Entry cacheEntry;
                if (!cache.Entries.TryGetValue(actionDescriptor, out cacheEntry))
                {
                    var filterFactoryResult = FilterFactory.GetAllFilters(_filterProviders, controllerContext);
                    filters = filterFactoryResult.Filters;
    
                    var executor = ObjectMethodExecutor.Create(
                        actionDescriptor.MethodInfo,
                        actionDescriptor.ControllerTypeInfo);
    
                    cacheEntry = new Entry(filterFactoryResult.CacheableFilters, executor);
                    cacheEntry = cache.Entries.GetOrAdd(actionDescriptor, cacheEntry);
                }
                else
                {
                    // Filter instances from statically defined filter descriptors + from filter providers
                    filters = FilterFactory.CreateUncachedFilters(_filterProviders, controllerContext, cacheEntry.FilterItems);
                }
    
                return new ControllerActionInvokerState(filters, cacheEntry.ActionMethodExecutor);
            }
    

        主要看下第10行到第15行代码。首先通过FilterFactory获取到跟当前动作相关联的过滤器信息集合,然后通过ObjectMethodExecutor.Create创建一个ObjectMethodExecutor对象,创建好后进行缓存。

      其实到这里我们已经知道IActionInvokder就是一个ControllerActionInvoker,然后调用该对象的InvokeAsync方法开始动作执行。最新版本实现采用了状态机(如果概念上错误,欢迎大家拍砖指正)的特点,执行时在不同状态之间进行切换,最终完成处理。而这部分工作就是在Next方法里实现的。方法真正执行实在State.ActionInside状态时执行,在此状态下通过调用InvokeActionMethodAsync完成控制器方法的执行,主要代码如下:

                    //下面的代码就是根据方法返回值类型不同,实现不同的逻辑
                    var returnType = executor.MethodReturnType;
                    if (returnType == typeof(void))
                    {
                        executor.Execute(controller, orderedArguments);
                        result = new EmptyResult();
                    }
                    else if (returnType == typeof(Task))
                    {
                        await (Task)executor.Execute(controller, orderedArguments);
                        result = new EmptyResult();
                    }
                    else if (executor.TaskGenericType == typeof(IActionResult))
                    {
                        result = await (Task<IActionResult>)executor.Execute(controller, orderedArguments);
                        if (result == null)
                        {
                            throw new InvalidOperationException(
                                Resources.FormatActionResult_ActionReturnValueCannotBeNull(typeof(IActionResult)));
                        }
                    }
                    else if (executor.IsTypeAssignableFromIActionResult)
                    {
                        if (_executor.IsMethodAsync)
                        {
                            result = (IActionResult)await _executor.ExecuteAsync(controller, orderedArguments);
                        }
                        else
                        {
                            result = (IActionResult)_executor.Execute(controller, orderedArguments);
                        }
    
                        if (result == null)
                        {
                            throw new InvalidOperationException(
                                Resources.FormatActionResult_ActionReturnValueCannotBeNull(_executor.TaskGenericType ?? returnType));
                        }
                    }
                    else if (!executor.IsMethodAsync)
                    {
                        var resultAsObject = executor.Execute(controller, orderedArguments);
                        result = resultAsObject as IActionResult ?? new ObjectResult(resultAsObject)
                        {
                            DeclaredType = returnType,
                        };
                    }
                    else if (executor.TaskGenericType != null)
                    {
                        var resultAsObject = await executor.ExecuteAsync(controller, orderedArguments);
                        result = resultAsObject as IActionResult ?? new ObjectResult(resultAsObject)
                        {
                            DeclaredType = executor.TaskGenericType,
                        };
                    }
                    else
                    {
                        // This will be the case for types which have derived from Task and Task<T> or non Task types.
                        throw new InvalidOperationException(Resources.FormatActionExecutor_UnexpectedTaskInstance(
                            executor.MethodInfo.Name,
                            executor.MethodInfo.DeclaringType));
                    }
    
                    _result = result;
                 
                
    
            }
    

      无论是哪种返回值类型,都是通过调用executor.Execute完成控制器方法调用,并获取结果,executor就是上面提到的ObjectMethodExecutor,我们只看下Execute方法实现:

    public object Execute(object target, object[] parameters)
            {
                return _executor(target, parameters);
            }
    

      这里面又是一个_executor,它是一个delegate object ActionExecutor(object target, object[] parameters)委托类型,它是在实例化ObjectMethodInvoker时通过GetExecutor方法创建的,采用的是动态lambda表达式,有了这个委托对象,就可以执行控制器方法了。

        方法执行后,会得到方法返回结果,然后进入Result相关状态流程,直到State.ResultInside状态时,调用InvokeResultAsync方法执行动作结果,具体代码如下:

    protected async Task InvokeResultAsync(IActionResult result)
            {
                var actionContext = _actionContext;
    
                _diagnosticSource.BeforeActionResult(actionContext, result);
    
                try
                {
                    await result.ExecuteResultAsync(actionContext);
                }
                finally
                {
                    _diagnosticSource.AfterActionResult(actionContext, result);
                }
            }
    

      到这里一个控制器动作就算执行完了,需要指出的是文章只介绍了主体流程,还有很多其他执行状态文章中没提到。

  • 相关阅读:
    02.02.03第3章 餐饮项目案例(Power BI商业智能分析)
    02.02.02 第2章 制作power bi图表(Power BI商业智能分析)
    MySQL 目录结构信息
    Commons-FileUpload 文件上传(模板)
    Commons-FileUpload 常用API
    Java DOM方式解析XML(模板)
    常用的节点类型
    MySQL权限及登陆、退出方法
    Java 锁
    线程的状态
  • 原文地址:https://www.cnblogs.com/dxp909/p/6617200.html
Copyright © 2020-2023  润新知