在理清路由的工作流程后,接下来需要考虑的,是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;
}
...
}
}
}

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

.NET Core开发日志——Controller的更多相关文章

  1. C#实现多级子目录Zip压缩解压实例 NET4.6下的UTC时间转换 [译]ASP.NET Core Web API 中使用Oracle数据库和Dapper看这篇就够了 asp.Net Core免费开源分布式异常日志收集框架Exceptionless安装配置以及简单使用图文教程 asp.net core异步进行新增操作并且需要判断某些字段是否重复的三种解决方案 .NET Core开发日志

    C#实现多级子目录Zip压缩解压实例 参考 https://blog.csdn.net/lki_suidongdong/article/details/20942977 重点: 实现多级子目录的压缩, ...

  2. .NET Core开发日志——Entity Framework与PostgreSQL

    Entity Framework在.NET Core中被命名为Entity Framework Core.虽然一般会用于对SQL Server数据库进行数据操作,但其实它还支持其它数据库,这里就以Po ...

  3. .NET Core开发日志——RequestDelegate

    本文主要是对.NET Core开发日志--Middleware的补遗,但是会从看起来平平无奇的RequestDelegate开始叙述,所以以其作为标题,也是合情合理. RequestDelegate是 ...

  4. .NET Core开发日志——从搭建开发环境开始

    .NET Core自2016年推出1.0版本开始,到目前已是2.1版本,在其roadmap计划里明年更会推出3.0版本,发展不可不谓之迅捷.不少公司在经过一个谨慎的观望期后,也逐步开始将系统升级至最新 ...

  5. .NET Core开发日志——Edge.js

    最近在项目中遇到这样的需求:要将旧有系统的一部分业务逻辑集成到新的自动化流程工具中.这套正在开发的自动化工具使用的是C#语言,而旧有系统的业务逻辑则是使用AngularJS在前端构建而成.所以最初的考 ...

  6. .NET Core开发日志——Model Binding

    ASP.NET Core MVC中所提供的Model Binding功能简单但实用,其主要目的是将请求中包含的数据映射到action的方法参数中.这样就避免了开发者像在Web Forms时代那样需要从 ...

  7. .NET Core开发日志——简述路由

    有过ASP.NET或其它现代Web框架开发经历的开发者对路由这一名字应该不陌生.如果要用一句话解释什么是路由,可以这样形容:通过对URL的解析,指定相应的处理程序. 回忆下在Web Forms应用程序 ...

  8. .NET Core开发日志——GraphQL

    GraphQL是什么 GraphQL既是一种用于API的查询语言也是一种通过使用对应数据的类型系统,执行数据查询的服务端运行时.GraphQL没有局限于任何数据库或存储引擎,而是通过既有代码及数据获得 ...

  9. .NET Core开发日志——OData

    简述 OData,即Open Data Protocol,是由微软在2007年推出的一款开放协议,旨在通过简单.标准的方式创建和使用查询式及交互式RESTful API. 类库 在.NET Core中 ...

随机推荐

  1. MySql之插入操作

    一:插入一行数据 INSERT INTO tableName(列名...) VALUES(对应列名的值); 二:插入多行 INSERT INTO tableName(列名...) VALUES(对应列 ...

  2. 【H5动画】谈谈canvas动画的闪烁问题

    一般来说,在H5开发中,使用canvas往往只是为了展示一些简单的图表或者简单短小的动画,很少考虑到有闪烁的问题. 最近,在手机QQ魔法表情的项目中,就遇到了奇葩的闪烁问题. 这里说的闪烁,是指动画刚 ...

  3. 利用Xmanager Enterprise 5的passive显示远程linux主机图形化信息

    问题描述: 最初的需求是,安装oracle数据(第一次安装都是图形化linxu进去一步步操作,后续发现可以命令静默安装不调用图形化,学习就是步步入深,方得始终),最初实现window弹出linux主机 ...

  4. django --- DetailView源码分析

    [背景] 最近在看django官方文档的class-based-views这一节的时候一直不得要领,感觉自己清楚,但是回想起来又没有脉络:于是没有办法只 能是“暗中观察”django的源码了. 刚打开 ...

  5. 第一部分:开发前的准备-第三章 Application 基本原理

    第3章 应用程序基本原理 首先我们需要强调一下Android 应用程序是用java写的.Android SDK工具编译代码并把资源文件和数据打包成一个文件.这个名字的扩展名是.APK.要在androi ...

  6. Spring Boot 2.0 整合Thymeleaf 模板引擎

    本节将和大家一起实战Spring Boot 2.0 和thymeleaf 模板引擎 1. 创建项目 2. 使用Spring Initlizr 快速创建Spring Boot 应用程序 3. 填写项目配 ...

  7. Atitit.pagging  翻页功能解决方案专题 与 目录大纲 v3 r44.docx

    Atitit.pagging  翻页功能解决方案专题 与 目录大纲 v3 r44.docx 1.1. 翻页的重要意义1 1.2. Dep废弃文档   paip.js翻页分页pageing组件.txt1 ...

  8. python 函数的参数的几种类型

    定义函数的时候,我们把参数的名字和位置确定下来,函数的接口定义就完成了.对于函数的调用者来说,只需要知道如何传递正确的参数,以及函数将返回什么样的值就够了,函数内部的复杂逻辑被封装起来,调用者无需了解 ...

  9. Manager升职了

    公司去年从每年七月份公布officer升职改成了每年四月份公布. 早上收到大头发给全公司的邮件,赫然发现Manager升了一级到VP,虽然是金融公司,但我司的VP好像会比银行多一点点福利,比如额外假期 ...

  10. Java知多少(36)内部类及其实例化

    在 Java 中,允许在一个类(或方法.语句块)的内部定义另一个类,称为内部类(Inner Class),有时也称为嵌套类(Nested Class). 内部类和外层封装它的类之间存在逻辑上的所属关系 ...