上文已经完成了ControllerFactory的创建,接下来就是调用其CreateController()方法创建Controller了。

DefaultControllerFactory中CreateController()的实现:

        public virtual IController CreateController(RequestContext requestContext, string controllerName)
{
//...
Type controllerType = GetControllerType(requestContext, controllerName);
IController controller = GetControllerInstance(requestContext, controllerType);
return controller;
}

很明显,首先根据controllerName获得controller类型,再根据controller类型获得controller实例。

先看GetControllerType()方法:

 protected internal virtual Type GetControllerType(RequestContext requestContext, string controllerName)
{
RouteData routeData = requestContext.RouteData;
if (routeData != null && routeData.HasDirectRouteMatch())
{
return GetControllerTypeFromDirectRoute(routeData);
} // first search in the current route's namespace collection
object routeNamespacesObj;
Type match;
if (routeData.DataTokens.TryGetValue(RouteDataTokenKeys.Namespaces, out routeNamespacesObj))
{
IEnumerable<string> routeNamespaces = routeNamespacesObj as IEnumerable<string>;
if (routeNamespaces != null && routeNamespaces.Any())
{
HashSet<string> namespaceHash = new HashSet<string>(routeNamespaces, StringComparer.OrdinalIgnoreCase);
match = GetControllerTypeWithinNamespaces(routeData.Route, controllerName, namespaceHash); // the UseNamespaceFallback key might not exist, in which case its value is implicitly "true"
if (match != null || false.Equals(routeData.DataTokens[RouteDataTokenKeys.UseNamespaceFallback]))
{
// got a match or the route requested we stop looking
return match;
}
}
} // then search in the application's default namespace collection
if (ControllerBuilder.DefaultNamespaces.Count > )
{
HashSet<string> namespaceDefaults = new HashSet<string>(ControllerBuilder.DefaultNamespaces, StringComparer.OrdinalIgnoreCase);
match = GetControllerTypeWithinNamespaces(routeData.Route, controllerName, namespaceDefaults);
if (match != null)
{
return match;
}
} // if all else fails, search every namespace
return GetControllerTypeWithinNamespaces(routeData.Route, controllerName, null /* namespaces */);
}

关于DirectRouteMatch先留个坑,以后填。

首先根据当前路由的命名空间查找controller,如果查找失败,则查找当前ControllerBuilder的默认命名空间,最后查找每个命名空间。我们注意到这三个步骤都调用了GetControllerTypeWithinNamespaces()方法,那么它具体怎么实现呢?

以下既是GetControllerTypeWithinNamespaces()的具体实现:

private Type GetControllerTypeWithinNamespaces(RouteBase route, string controllerName, HashSet<string> namespaces)
{
// Once the master list of controllers has been created we can quickly index into it
ControllerTypeCache.EnsureInitialized(BuildManager); ICollection<Type> matchingTypes = ControllerTypeCache.GetControllerTypes(controllerName, namespaces);
switch (matchingTypes.Count)
{
case :
// no matching types
return null; case :
// single matching type
return matchingTypes.First(); default:
// multiple matching types
throw CreateAmbiguousControllerException(route, controllerName, matchingTypes);
}
}

看来具体的查找又和一个ControllerTypeCache类型的对象有关,并且只在找到唯一controller类型时将它返回。

那么来看看ControllerTypeCache类型吧:

internal sealed class ControllerTypeCache
{
private volatile Dictionary<string, ILookup<string, Type>> _cache;
private object _lockObj = new object();
public void EnsureInitialized(IBuildManager buildManager)
{
if (_cache == null)
{
lock (_lockObj)
{
if (_cache == null)
{
List<Type> controllerTypes = TypeCacheUtil.GetFilteredTypesFromAssemblies(TypeCacheName, IsControllerType, buildManager);
var groupedByName = controllerTypes.GroupBy(
t => t.Name.Substring(, t.Name.Length - "Controller".Length),
StringComparer.OrdinalIgnoreCase);
_cache = groupedByName.ToDictionary(
g => g.Key,
g => g.ToLookup(t => t.Namespace ?? String.Empty, StringComparer.OrdinalIgnoreCase),
StringComparer.OrdinalIgnoreCase);
}
}
}
} public ICollection<Type> GetControllerTypes(string controllerName, HashSet<string> namespaces)
{
HashSet<Type> matchingTypes = new HashSet<Type>(); ILookup<string, Type> namespaceLookup;
if (_cache.TryGetValue(controllerName, out namespaceLookup))
{
// this friendly name was located in the cache, now cycle through namespaces
if (namespaces != null)
{
foreach (string requestedNamespace in namespaces)
{
foreach (var targetNamespaceGrouping in namespaceLookup)
{
if (IsNamespaceMatch(requestedNamespace, targetNamespaceGrouping.Key))
{
matchingTypes.UnionWith(targetNamespaceGrouping);
}
}
}
}
else
{
// if the namespaces parameter is null, search *every* namespace
foreach (var namespaceGroup in namespaceLookup)
{
matchingTypes.UnionWith(namespaceGroup);
}
}
} return matchingTypes;
}
//...
)

原来 EnsureInitialized()用来确保_cache被初始化,而_cache则是根据 buildManager.GetReferencedAssemblies()得到的所有引用的程序集,将程序集中所有controller取出并将contoller.Name去掉controller后缀作为键的字典类型,字典的值又是一个以controller所在Namespace为键,controller实际类型为值的Lookup类型。

接下来的GetControllerTypes()就很明显了,就是根据传来的controllerName和namespaces参数查找controller类型并返回。

至此我们便了解了获得controller类型的整个流程,接下来便是controller实例的创建了。

GetControllerInstance()的实现很简单:

protected internal virtual IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
return ControllerActivator.Create(requestContext, controllerType);
}

真正的实现还是在IControllerActivator类型实例的Create()方法中,先看下这个实例如何生成:

         private IResolver<IControllerActivator> _activatorResolver;
private IControllerActivator _controllerActivator;
internal DefaultControllerFactory(IControllerActivator controllerActivator, IResolver<IControllerActivator> activatorResolver, IDependencyResolver dependencyResolver)
{
if (controllerActivator != null)
{
_controllerActivator = controllerActivator;
}
else
{
_activatorResolver = activatorResolver ?? new SingleServiceResolver<IControllerActivator>(
() => null,
new DefaultControllerActivator(dependencyResolver),
"DefaultControllerFactory constructor"
);
}
} private IControllerActivator ControllerActivator
{
get
{
if (_controllerActivator != null)
{
return _controllerActivator;
}
_controllerActivator = _activatorResolver.Current;
return _controllerActivator;
}
}

这我们就很熟悉了--和之前ControllerFactory是一样的。

最后看一下默认ControllerActivator--DefaultControllerActivator的实现:

 private class DefaultControllerActivator : IControllerActivator
{
private Func<IDependencyResolver> _resolverThunk;
public DefaultControllerActivator(IDependencyResolver resolver)
{
if (resolver == null)
{
_resolverThunk = () => DependencyResolver.Current;
}
else
{
_resolverThunk = () => resolver;
}
} public IController Create(RequestContext requestContext, Type controllerType)
{return (IController)(_resolverThunk().GetService(controllerType) ?? Activator.CreateInstance(controllerType));
}
}

没什么复杂的,也和之前创建ControllerFactory一样,默认实现为DefaultDependencyResolver中的GetService()方法:利用反射创建一个Controller。

public object GetService(Type serviceType)
{
// Since attempting to create an instance of an interface or an abstract type results in an exception, immediately return null
// to improve performance and the debugging experience with first-chance exceptions enabled.
if (serviceType.IsInterface || serviceType.IsAbstract)
{
return null;
} try
{
return Activator.CreateInstance(serviceType);
}
catch
{
return null;
}
}

至此,我们终于了解了一个Controller的全过程。

MVC5 Controller简要创建过程(2):由ControllerFactory创建Controller的更多相关文章

  1. Spring MVC 原理探秘 - 容器的创建过程

    1.简介 在上一篇文章中,我向大家介绍了 Spring MVC 是如何处理 HTTP 请求的.Spring MVC 可对外提供服务时,说明其已经处于了就绪状态.再次之前,Spring MVC 需要进行 ...

  2. windows进程/线程创建过程 --- windows操作系统学习

    有了之前的对进程和线程对象的学习的铺垫后,我们现在可以开始学习windows下的进程创建过程了,我将尝试着从源代码的层次来分析在windows下创建一个进程都要涉及到哪些步骤,都要涉及到哪些数据结构. ...

  3. 0003 - 基于xml的Spring Bean 的创建过程

    一.目录 前言 创建 Bean 容器 加载 Bean 定义 创建 Bean Spring Bean 创建过程中的设计模式 总结 二.前言 2.1 Spring 使用配置 ApplicationCont ...

  4. Android深入理解Context(二)Activity和Service的Context创建过程

    前言 上一篇文章我们学习了Context关联类和Application Context的创建过程,这一篇我们接着来学习Activity和Service的Context创建过程.需要注意的是,本篇的知识 ...

  5. Spring源码解析 – AnnotationConfigApplicationContext容器创建过程

    Spring在BeanFactory基础上提供了一些列具体容器的实现,其中AnnotationConfigApplicationContext是一个用来管理注解bean的容器,从AnnotationC ...

  6. Python之变量的创建过程

    Python之变量的创建过程 一.变量创建过程 首先,当我们定义了一个变量name = 'Kwan'的时候,在内存中其实是做了这样一件事: 程序开辟了一块内存空间,将'Kwan'存储进去,再让变量名n ...

  7. Java对象的创建过程:类的初始化与实例化

    一.Java对象创建时机 我们知道,一个对象在可以被使用之前必须要被正确地实例化.在Java代码中,有很多行为可以引起对象的创建,最为直观的一种就是使用new关键字来调用一个类的构造函数显式地创建对象 ...

  8. MVC5 Controller简要创建过程(1):ControllerFactory的创建

    即将离职,闲来无事回顾下MVC的源码,到了Controller创建这里,由于流程有点复杂,鉴于自己记性不太好,索性就记录一下吧,方便日后参照. 首先看MvcHandler: public class ...

  9. .NET/ASP.NET MVC Controller 控制器(IController控制器的创建过程)

    阅读目录: 1.开篇介绍 2.ASP.NETMVC IControllerFactory 控制器工厂接口 3.ASP.NETMVC DefaultControllerFactory 默认控制器工厂 4 ...

随机推荐

  1. JavaEE Tutorials (25) - 使用Java EE拦截器

    25.1拦截器概述380 25.1.1拦截器类381 25.1.2拦截器生命周期381 25.1.3拦截器和CDI38125.2使用拦截器381 25.2.1拦截方法调用382 25.2.2拦截生命周 ...

  2. java 科学计数法表示转换

    BigDecimal strScien = new BigDecimal("9.67953970412123E-05"); System.out.println(strScien. ...

  3. ubuntu下google 拼音输入法的安装

    google拼音输入法安装 (1).获代替码:(没有git的先安装git:sudoapt-get install git-core) $>gitclone git://github.com/tc ...

  4. 逆向x64-small-trick

        在逆向一些x64的代码时,会发现有一小段汇编代码理解不了,这个时候回想,要是能单独执行这一小段汇编就好了.现在我就介绍一个我的解决方法:很小汇编一段代码,但是不好理解,我就把它单独写成了一个函 ...

  5. 线上应用故障排查之一:高CPU占用

    一个应用占用CPU很高,除了确实是计算密集型应用之外,通常原因都是出现了死循环. (友情提示:本博文章欢迎转载,但请注明出处:hankchen,http://www.blogjava.net/hank ...

  6. IE下图片切换的时候,图片总是切换不成功---根本问题是IE缓存图片

    作为WEB设计者,为了在网页展示上加强用户体验,经常会利用图象载入显示状态方法,这自然需要Image对象的onload事件. 在firefox浏览器下完成开发后,可是在IE浏览器中进行调试总不能被调用 ...

  7. zoj 1067

    输入一组RGB颜色列表,每行一个颜色,是三个从0~255的整数 前16行是目标颜色组,-1 -1 -1表示结束   16组颜色以后接下来的几行是需要判断的,看它和哪个颜色的距离D最小,找出这个对应的颜 ...

  8. zoj1074 To the Max

    题目很简单,求一个连续的最大子矩阵的值. zoj上的数据非常弱. 首先爆搜是O(N^4),10^8的复杂度略高,那么我们可以处理一下其中一维的前缀和,降一阶,然后按照连续最大子序列来处理,因为可能为负 ...

  9. centos6.7配置git服务器

    1.yum install -y git 2.adduser git 3.cd /data/git 没有则创建该目录 git init --bare test.git;创建一个裸仓库,没有工作区,不需 ...

  10. iOS中不透明度的查看

    模拟器工具条 Debug-->Color Blended Layers 即中文显示下 调试 -->颜色混合层 绿色代表不透明部分,红色代表透明部分,红色越多对性能影响越大