Controller的创建
在ControllerBuilder类中设置ControllerFactory,然后使用ControllerFactory创建Controller。 http请求在进入httphandler映射处理时,通过ControllerBuilder的Current获取ControllerFactory,然后使用默认或者注册的(如果注册地话)ControllerFactory创建controller。默认的工厂是一个DefaultControllerFactory对象,由下面代码可以看出。
internal ControllerBuilder(IResolver<IControllerFactory> serviceResolver)
{
ControllerBuilder controllerBuilder = this;
IResolver<IControllerFactory> resolver = serviceResolver;
if (resolver == null)
resolver = (IResolver<IControllerFactory>) new SingleServiceResolver<IControllerFactory>((Func<IControllerFactory>) (() => this._factoryThunk()),(IControllerFactory) new DefaultControllerFactory()
{
ControllerBuilder = this
}, "ControllerBuilder.GetControllerFactory");
controllerBuilder._serviceResolver = resolver;
}
而Controller的产生是通过DefaultControllerFactory的CreateController来实现的,代码如下:
public virtual IController CreateController(RequestContext requestContext, string controllerName)
{
if (requestContext == null)
throw new ArgumentNullException("requestContext");
if (string.IsNullOrEmpty(controllerName))
throw new ArgumentException(MvcResources.Common_NullOrEmpty, "controllerName");
Type controllerType = this.GetControllerType(requestContext, controllerName);
return this.GetControllerInstance(requestContext, controllerType);
}
然后查看GetControllerType方法:
protected internal virtual Type GetControllerType(RequestContext requestContext, string controllerName)
{
if (string.IsNullOrEmpty(controllerName))
throw new ArgumentException(MvcResources.Common_NullOrEmpty, "controllerName");
object obj;
if (requestContext != null && requestContext.RouteData.DataTokens.TryGetValue("Namespaces", out obj))
{
IEnumerable<string> enumerable = obj as IEnumerable<string>;
if (enumerable != null && Enumerable.Any<string>(enumerable))
{
HashSet<string> namespaces = new HashSet<string>(enumerable, (IEqualityComparer<string>) StringComparer.OrdinalIgnoreCase);
Type withinNamespaces = this.GetControllerTypeWithinNamespaces(requestContext.RouteData.Route, controllerName, namespaces);
if (withinNamespaces != (Type) null || false.Equals(requestContext.RouteData.DataTokens["UseNamespaceFallback"]))
return withinNamespaces;
}
}
if (this.ControllerBuilder.DefaultNamespaces.Count > 0)
{
HashSet<string> namespaces = new HashSet<string>((IEnumerable<string>) this.ControllerBuilder.DefaultNamespaces, (IEqualityComparer<string>) StringComparer.OrdinalIgnoreCase);
Type withinNamespaces = this.GetControllerTypeWithinNamespaces(requestContext.RouteData.Route, controllerName, namespaces);
if (withinNamespaces != (Type) null)
return withinNamespaces;
}
return this.GetControllerTypeWithinNamespaces(requestContext.RouteData.Route, controllerName, (HashSet<string>) null);
}
可以看到最终都归结到同一个方法GetControllerTypeWithinNamespaces中,代码如下:
private Type GetControllerTypeWithinNamespaces(RouteBase route, string controllerName, HashSet<string> namespaces)
{
this.ControllerTypeCache.EnsureInitialized(this.BuildManager);
ICollection<Type> controllerTypes = this.ControllerTypeCache.GetControllerTypes(controllerName, namespaces);
switch (controllerTypes.Count)
{
case 0:
return (Type) null;
case 1:
return Enumerable.First<Type>((IEnumerable<Type>) controllerTypes);
default:
throw DefaultControllerFactory.CreateAmbiguousControllerException(route, controllerName, controllerTypes);
}
}
而方法EnsureInitialized()是通过IBuildManager获取程序中所有实现了IController的类型,然后在这些类型里用路由数据或者ControllerBuilder中的命名空间和controller的名称进行匹配,如果没有匹配,返回null,如果有一个匹配,返回,如果有多个,抛出异常!
现在获取到了controllerType的类型,然后返回到工厂的CreateController的最后一步,查看GetControllerInstance方法,代码如下:
protected internal virtual IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if (controllerType == (Type) null)
{
throw new HttpException(404, string.Format((IFormatProvider) CultureInfo.CurrentCulture, MvcResources.DefaultControllerFactory_NoControllerFound, new object[1]
{
(object) requestContext.HttpContext.Request.Path
}));
}
else
{
if (typeof (IController).IsAssignableFrom(controllerType))
return this.ControllerActivator.Create(requestContext, controllerType);
throw new ArgumentException(string.Format((IFormatProvider) CultureInfo.CurrentCulture, MvcResources.DefaultControllerFactory_TypeDoesNotSubclassControllerBase, new object[1]
{
(object) controllerType
}), "controllerType");
}
}
可以看到,这个时候又使用到了另外一个对象ControllerActivator,由DefaultControllerFactory的构造函数可以看出
internal DefaultControllerFactory(IControllerActivator controllerActivator, IResolver<IControllerActivator> activatorResolver, IDependencyResolver dependencyResolver)
{
if (controllerActivator != null)
this._controllerActivator = controllerActivator;
else
this._activatorResolver = activatorResolver ?? (IResolver<IControllerActivator>) new SingleServiceResolver<IControllerActivator>((Func<IControllerActivator>) (() => (IControllerActivator) null),(IControllerActivator) new DefaultControllerFactory.DefaultControllerActivator(dependencyResolver), "DefaultControllerFactory constructor");
}
默认使用的是实现了接口IResolver<TService>的SingleServiceResolver<TService>对象默认注册的一个内部对象DefaultControllerActivator,然后调用它的create方法,代码如下:
public IController Create(RequestContext requestContext, Type controllerType)
{
try
{
return (IController) (this._resolverThunk().GetService(controllerType) ?? Activator.CreateInstance(controllerType));
}
catch (Exception ex)
{
throw new InvalidOperationException(string.Format((IFormatProvider) CultureInfo.CurrentCulture, MvcResources.DefaultControllerFactory_ErrorCreatingController, new object[1]
{
(object) controllerType
}), ex);
}
}
而DefaultControllerActivator对象中的属性_resolverThunk是一个Func<IDependencyResolver> _resolverThunk委托对象,我们通过DefaultControllerFactory构造函数中调用的new DefaultControllerFactory.DefaultControllerActivator(dependencyResolver),可以看到DefaultControllerActivator的构造函数
public DefaultControllerActivator(IDependencyResolver resolver)
{
if (resolver == null)
this._resolverThunk = (Func<IDependencyResolver>) (() => DependencyResolver.Current);
else
this._resolverThunk = (Func<IDependencyResolver>) (() => resolver);
}
对它的设置,如果在自己实现的ControllerFactory的构造函数中传递了自己定义的一个IDependencyResolver对象或者DependencyResolver的SetResolver方法设置了一个自定义的IDependencyResolver对象,就会使用它,如果没有,则使用默认的DependencyResolver.Current,可以看到DependencyResolver.Current是一个实现了IDependencyResolver接口对象的引用,从他的构造函数
public DependencyResolver()
{
this.InnerSetResolver((IDependencyResolver) new DependencyResolver.DefaultDependencyResolver());
}
看出它使用的是一个内部私有的对象DefaultDependencyResolver,
private class DefaultDependencyResolver : IDependencyResolver
{
public object GetService(Type serviceType)
{
if (!serviceType.IsInterface)
{
if (!serviceType.IsAbstract)
{
try
{
return Activator.CreateInstance(serviceType);
}
catch
{
return (object) null;
}
}
}
return (object) null;
} public IEnumerable<object> GetServices(Type serviceType)
{
return Enumerable.Empty<object>();
}
}
它的GetService方法,通过反射创建了我们需要的controller对象,由此,controller创建成功!
Area中controller的解析过程:
首先我们知道,在程序刚启动时,我们会调用AreaRegistration.RegisterAllAreas()方法:
internal static void RegisterAllAreas(RouteCollection routes, IBuildManager buildManager, object state)
{
foreach (Type type in TypeCacheUtil.GetFilteredTypesFromAssemblies("MVC-AreaRegistrationTypeCache.xml", new Predicate<Type>(AreaRegistration.IsAreaRegistrationType), buildManager))
((AreaRegistration) Activator.CreateInstance(type)).CreateContextAndRegister(routes, state);
}
它是先查找出程序中所有实现了AreaRegistration的区域对象,然后创建他们的实例,调用实例的CreateContextAndRegister方法,来创建AreaRegistrationContext对象,
internal void CreateContextAndRegister(RouteCollection routes, object state)
{
AreaRegistrationContext context = new AreaRegistrationContext(this.AreaName, routes, state);
string @namespace = this.GetType().Namespace;
if (@namespace != null)
context.Namespaces.Add(@namespace + ".*");
this.RegisterArea(context);
}
然后调用RegisterArea方法,对路由进行注册,可以看出,这个时候还做了一个额外的事情,就是给上下文的属性Namespaces添加了一个以(区域注册对象所在命名空间+".*")的命名空间,这个最后会用于解析controller对象,通过后续代码可以看出,这个上下文的Namespaces会被使用。
而一般的RegisterArea方法就是通过我们自己创建的区域注册对象来重写实现的,是通过调用AreaRegistrationContext对象的MapRoute()方法来实现路由注册的.
public Route MapRoute(string name, string url, object defaults, object constraints, string[] namespaces)
{
if (namespaces == null && this.Namespaces != null)
namespaces = Enumerable.ToArray<string>((IEnumerable<string>) this.Namespaces);
Route route = RouteCollectionExtensions.MapRoute(this.Routes, name, url, defaults, constraints, namespaces);
route.DataTokens["area"] = (object) this.AreaName;
bool flag = namespaces == null || namespaces.Length == 0;
route.DataTokens["UseNamespaceFallback"] = (object) (bool) (flag ? 1 : 0);
return route;
}
这个方法中我们看到如果注册路由时没有指定命名空间,则会把上下文的Namespaces属性拿来使用,除了注册路由之外,这个方法还做了一步工作,在路由数据的DataTokens中添加了一个以UseNamespaceFallback为key的数据,它的值是通过判断如果注册路由的命名空间参数和上下文的Namespaces都为空的情况下,为1,否则为0;为1,则在解析controller时需要使用controllerBuilder中的DefaultNamespaces属性的值中的命名空间。这个逻辑我们可以再DefaultControllerFactory的GetControllerType()方法中可以看到!
而且我们可以看到路由数据RouteData中表示区域的area的值是存在DataTokens属性中
Controller的创建的更多相关文章
- MVC5框架解析之Controller的创建
在上一讲中我们介绍了MvcHandler,知道在Handler里面注入两个接口属性分别为IControllerFactory和IController的factory和controller.并且通过IO ...
- MVC5 Controller简要创建过程(2):由ControllerFactory创建Controller
上文已经完成了ControllerFactory的创建,接下来就是调用其CreateController()方法创建Controller了. DefaultControllerFactory中Crea ...
- MVC5 Controller简要创建过程(1):ControllerFactory的创建
即将离职,闲来无事回顾下MVC的源码,到了Controller创建这里,由于流程有点复杂,鉴于自己记性不太好,索性就记录一下吧,方便日后参照. 首先看MvcHandler: public class ...
- LoadRunner性能测试中Controller场景创建需注意的几点
在LR工具做性能测试中,最关键的一步是Controller场景的设计,因为场景的设计与测试用例的设计相关联,而测试用例的执行,直接影响最终的测试结果是怎么的,因此,我们每设计一种场景,就有可能是一个测 ...
- Spring Taco Cloud——Controller的创建(含SpringMVC执行过程&SpringBoot&Spring三者解释及关联)
在记录这次控制器编写前,对于Spring的感觉就是经常提这样代码好简洁,这样好方便,这个是用来干嘛的诸如之类的话. What is Spring ?这是我想问自己的,一直认为是简化代码利于工程的开源框 ...
- .NET/ASP.NET MVC Controller 控制器(IController控制器的创建过程)
阅读目录: 1.开篇介绍 2.ASP.NETMVC IControllerFactory 控制器工厂接口 3.ASP.NETMVC DefaultControllerFactory 默认控制器工厂 4 ...
- 三、ASP.NET MVC Controller 控制器(二:IController控制器的创建过程)
阅读目录: 1.开篇介绍 2.ASP.NETMVC IControllerFactory 控制器工厂接口 3.ASP.NETMVC DefaultControllerFactory 默认控制器工厂 4 ...
- ASP.NET Web API 框架研究 Controller创建过程与消息处理管道
现在我们从代码角度来看下,从消息处理管道末尾是怎么创建出Controller实例的.消息处理管道末端是一个叫HttpRoutingDispatcher的处理器,其内部完成路由后 ,会把消息派送给其内部 ...
- ASP.NET MVC Controller的激活
最近抽空看了一下ASP.NET MVC的部分源码,顺带写篇文章做个笔记以便日后查看. 在UrlRoutingModule模块中,将请求处理程序映射到了MvcHandler中,因此,说起Controll ...
随机推荐
- 首页自动生成静态化html
由于平台老是出现间歇性502.排查发现,php死进程过多耗费大量系统资源. 除了优化代码之外,静态化可以减少php进程.缓解一下服务器压力. 把首页生成html后,出现问题频率下降.所以需要做首页静态 ...
- SPSS中两种重复测量资料分析过程的比较
在SPSS中,有两个过程可以对重复测量资料进行分析:一种是一般线性模型的重复度量:一种是混合线性模型,对于同样的数据资料,使用两种过程分析出的内容不大一样,注意是内容而不是结果,只要操作正确,结果应该 ...
- css学习笔记 7
background-position属性值为百分比的时候,第一个百分比表示水平方向的距离,第二个表示垂直方向上的距离. text-indent的主要作用是为段落设置首行缩进,只能应用于块级元素.该属 ...
- java web 之 SpringMVC4.x配置
合肥程序员群:49313181. 合肥实名程序员群:128131462 (不愿透露姓名和信息者勿加入) Q Q:408365330 E-Mail:egojit@qq.com 综述: 有 ...
- 解决 笔记本键盘打字母却跳出数字来,每次都要按一遍Fn+Num LK 的问题
方法一. 开始-运行,输入“Regedit"命令进入注册表 HKEY_USERS\.DEFAULT\Control Panel\Keyboard 将 InitialKeyboardIndic ...
- 关于ViewPager、ViewFilpper、ViewFlow三种实现水平向滑动方式的比较
ViewPagerViewPager类提供了多界面切换的新效果.新效果有如下特征:[1] 当前显示一组界面中的其中一个界面.[2] 当用户通过左右滑动界面时,当前的屏幕显示当前界面和下一个界面的一部分 ...
- VHDL的参数写在一个vhd文件里
1 参数文件top_pkg.vhd
- php date("Y-m-d H:i:s") 出现警告信息
使用: $createtime=date("Y/m/d H:i:s", time()+16*60*60); $createtime=date("Y-m-d H:i:s&q ...
- Html.DropDownList
//获取直属父级列表 var parents = _MemberEditDTOService.GetParents(); var parentsItems = parents.Result.Selec ...
- php简写表达式,&& or || 缩写条件语句
有时候学的多了, 好多小细节 都忘了 ,比如 简单的表达式, 三元表达式 ?:; $aa or $bb 表达式 等等! 写一些简单的表达式,备忘! php用&&和||缩写条件语句 ...