MVC5 Controller简要创建过程(1):ControllerFactory的创建
即将离职,闲来无事回顾下MVC的源码,到了Controller创建这里,由于流程有点复杂,鉴于自己记性不太好,索性就记录一下吧,方便日后参照。
首先看MvcHandler:
public class MvcHandler : IHttpAsyncHandler, IHttpHandler, IRequiresSessionState
{
//...
private ControllerBuilder _controllerBuilder;
internal ControllerBuilder ControllerBuilder
{
get
{
if (_controllerBuilder == null)
{
_controllerBuilder = ControllerBuilder.Current;
}
return _controllerBuilder;
}
set { _controllerBuilder = value; }
}
//...
protected internal virtual void ProcessRequest(HttpContextBase httpContext)
{
IController controller;
IControllerFactory factory;
ProcessRequestInit(httpContext, out controller, out factory);
try
{
controller.Execute(RequestContext);
}
finally
{
factory.ReleaseController(controller);
}
} private void ProcessRequestInit(HttpContextBase httpContext, out IController controller, out IControllerFactory factory)
{
// ...
// Get the controller type
string controllerName = RequestContext.RouteData.GetRequiredString("controller"); // Instantiate the controller and call Execute
factory = ControllerBuilder.GetControllerFactory();
controller = factory.CreateController(RequestContext, controllerName);
//...
}
}
简而言之,controller通过实现IControllerFactory的工厂的CreateController()方法创建,而该工厂通过ControllerBuilder.GetControllerFactory()获得,而ControllerBuilder通过ControllerBuilder类型的一个静态属性Current获得,显然Current是ControllerBuilder类型的一个单例。
那么来看看ControllerBuidler:
public class ControllerBuilder
{
private static ControllerBuilder _instance = new ControllerBuilder();
private Func<IControllerFactory> _factoryThunk = () => null;
private HashSet<string> _namespaces = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
private IResolver<IControllerFactory> _serviceResolver;
public ControllerBuilder()
: this(null)
{
} internal ControllerBuilder(IResolver<IControllerFactory> serviceResolver)
{
_serviceResolver = serviceResolver ?? new SingleServiceResolver<IControllerFactory>(
() => _factoryThunk(),
new DefaultControllerFactory { ControllerBuilder = this },
"ControllerBuilder.GetControllerFactory");
} public static ControllerBuilder Current
{
get { return _instance; }
}
public IControllerFactory GetControllerFactory()
{
return _serviceResolver.Current;
} public void SetControllerFactory(IControllerFactory controllerFactory)
{
if (controllerFactory == null)
{
throw new ArgumentNullException("controllerFactory");
} _factoryThunk = () => controllerFactory;
}
//...
}
GetControllerFactory()方法返回一个IResolver<IControllerFactory>类型实例的Current属性,默认为SingleServiceResolver<IControllerFactory>类型。
以下是SingleServiceResolver<IControllerFactory>的部分实现:
internal class SingleServiceResolver<TService> : IResolver<TService>
where TService : class
{
private Lazy<TService> _currentValueFromResolver;
private Func<TService> _currentValueThunk;
private TService _defaultValue;
private Func<IDependencyResolver> _resolverThunk;
private string _callerMethodName; public SingleServiceResolver(Func<TService> currentValueThunk, TService defaultValue, string callerMethodName)
{
_resolverThunk = () => DependencyResolver.Current;
_currentValueFromResolver = new Lazy<TService>(GetValueFromResolver);
_currentValueThunk = currentValueThunk;
_defaultValue = defaultValue;
_callerMethodName = callerMethodName;
} internal SingleServiceResolver(Func<TService> staticAccessor, TService defaultValue, IDependencyResolver resolver, string callerMethodName)
: this(staticAccessor, defaultValue, callerMethodName)
{
if (resolver != null)
{
_resolverThunk = () => resolver;
}
} public TService Current
{
get { return _currentValueFromResolver.Value ?? _currentValueThunk() ?? _defaultValue; }
} private TService GetValueFromResolver()
{
TService result = _resolverThunk().GetService<TService>(); if (result != null && _currentValueThunk() != null)
{
return result;
}
}
由此可见Current属性返回的值有一个优先级:
优先级最低的是_defaultValue,_defaultValue在构造函数中通过参数传递进来,在之前的CotrollerBuilder中可以看到,这个默认值是一个DefaultFactory类型实例;
次优先级的是对_currentValueThunk委托的调用,也在构造函数中作为参数传递进来,默认返回Null,并且可以通过CotrollerBuilder的SetControllerFactory()方法进行设置;
最高优先级的是一个GetValueFromResolver()方法的返回值,并通过Lazy<>实现延迟执行,GetValueFromResolver()方法内部,首先是对_resolverThunk委托的调用,该委托可通过构造函数的参数传递,否则返回一个DependencyResolver的Current属性,DependencyResolver我们就比较熟悉了,它用于IOC容器的设置和构建,关于它篇幅所限在后面详解吧,该属性返回一个IDependencyResolver类型实例,默认为MVC内部的一个IOC容器DefaultDependencyResolver,由于默认TService类型是一个接口类型,所以DefaultDependencyResolver的GetService()方法默认返回Null。
ControllerFactory的整个创建过程就是这样了。
MVC5 Controller简要创建过程(1):ControllerFactory的创建的更多相关文章
- MVC5 Controller简要创建过程(2):由ControllerFactory创建Controller
上文已经完成了ControllerFactory的创建,接下来就是调用其CreateController()方法创建Controller了. DefaultControllerFactory中Crea ...
- Spring MVC 原理探秘 - 容器的创建过程
1.简介 在上一篇文章中,我向大家介绍了 Spring MVC 是如何处理 HTTP 请求的.Spring MVC 可对外提供服务时,说明其已经处于了就绪状态.再次之前,Spring MVC 需要进行 ...
- windows进程/线程创建过程 --- windows操作系统学习
有了之前的对进程和线程对象的学习的铺垫后,我们现在可以开始学习windows下的进程创建过程了,我将尝试着从源代码的层次来分析在windows下创建一个进程都要涉及到哪些步骤,都要涉及到哪些数据结构. ...
- 0003 - 基于xml的Spring Bean 的创建过程
一.目录 前言 创建 Bean 容器 加载 Bean 定义 创建 Bean Spring Bean 创建过程中的设计模式 总结 二.前言 2.1 Spring 使用配置 ApplicationCont ...
- Android深入理解Context(二)Activity和Service的Context创建过程
前言 上一篇文章我们学习了Context关联类和Application Context的创建过程,这一篇我们接着来学习Activity和Service的Context创建过程.需要注意的是,本篇的知识 ...
- Spring源码解析 – AnnotationConfigApplicationContext容器创建过程
Spring在BeanFactory基础上提供了一些列具体容器的实现,其中AnnotationConfigApplicationContext是一个用来管理注解bean的容器,从AnnotationC ...
- Python之变量的创建过程
Python之变量的创建过程 一.变量创建过程 首先,当我们定义了一个变量name = 'Kwan'的时候,在内存中其实是做了这样一件事: 程序开辟了一块内存空间,将'Kwan'存储进去,再让变量名n ...
- Java对象的创建过程:类的初始化与实例化
一.Java对象创建时机 我们知道,一个对象在可以被使用之前必须要被正确地实例化.在Java代码中,有很多行为可以引起对象的创建,最为直观的一种就是使用new关键字来调用一个类的构造函数显式地创建对象 ...
- .NET/ASP.NET MVC Controller 控制器(IController控制器的创建过程)
阅读目录: 1.开篇介绍 2.ASP.NETMVC IControllerFactory 控制器工厂接口 3.ASP.NETMVC DefaultControllerFactory 默认控制器工厂 4 ...
随机推荐
- Linux进程间通信——使用信号
一.什么是信号 用过Windows的我们都知道,当我们无法正常结束一个程序时,可以用任务管理器强制结束这个进程,但这其实是怎么实现的呢?同样的功能在Linux上是通过生成信号和捕获信号来实现的,运行中 ...
- 【DSA MOOC】有序向量二分查找的三个 版本
内容来自 TsinghuaX: 30240184X 数据结构(2015秋) 课程的Vector一章,对有序向量的二分查找有三个版本 三个版本的函数原型是一致的,都是 Rank search(T con ...
- PyCharm设置字体
pycharm 是很好的一个IDE,就是默认字体太小了,真的太小了,改字体的地方很隐晦.找了半天,贴图: 然后发现size 不能更改,所以,点击save as创建一个方案,然后修改自己的方案.这个时候 ...
- Linux学习笔记6-Linux根目录下各个目录的作用
/bin:存放最常用命令: /boot:启动Linux的核心文件: /dev:设备文件: /etc:存放各种配置文件: /home:用户主目录: /lib:系统最基本的动态链接共享库: /mnt:一 ...
- hdu1814 Peaceful Commission,2-sat
题目大意:一国有n个党派.每一个党派在议会中都有2个代表,现要组建和平委员会,要从每一个党派在议会的代表中选出1人,一共n人组成和平委员会.已知有一些代表之间存在仇恨,也就是说他们不能同一时候被选为和 ...
- Do we need other languages other than C and C++?
There were hundreds of or thousands of programming languages created since the invention of computer ...
- Bootstrap 简洁、直观、强悍、移动设备优先的前端开发框架,让web开发更迅速、简单。
http://v3.bootcss.com/ 从2.x升级到3.0版本 Bootstrap 3并不向后兼容Bootstrap v2.x.下面章节列出的内容可以作为从v2.x升级到v3.0的通用指南.如 ...
- 解决Mac OS Adobe Flash Builder 4.7 java heap space 问题【转】
1. 在Finder中打开Adobe Flash Builder 4.7的安装目录 2. 在Adobe Flash Builder 4.7.app上点击右键“Show Package contents ...
- C#整理2——C#的输入输出及基本类型
//输出 Console.WriteLine("摩西摩西"); Console.Write("hollo");不带回车的 注意: 1.注意大小写敏感.(快捷键操 ...
- c#中的数据类型简介(string)
Sting 字符串 引入话题 字符串是一个引用类型,从string数据类型的代码定义中也可以看出它实现了IEnumerable<char>接口和IEnumerable接口,因此字符串可以看 ...