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属性中

时间: 2024-10-10 08:49:10

Controller的创建的相关文章

MVC5框架解析之Controller的创建

在上一讲中我们介绍了MvcHandler,知道在Handler里面注入两个接口属性分别为IController和IControllerFactory.并且通过IOC容器ControllerBuilder进行创建对应的ControllerFactory,Mvc默认的ControllerFactory为DefaultControllerFactory:我们可以ControllerBuilder类中通过静态字段Current来修改静态属性_instance中的_SetControllerFactory

MVC5 Controller简要创建过程(2):由ControllerFactory创建Controller

上文已经完成了ControllerFactory的创建,接下来就是调用其CreateController()方法创建Controller了. DefaultControllerFactory中CreateController()的实现: public virtual IController CreateController(RequestContext requestContext, string controllerName) { //... Type controllerType = Get

MVC5 Controller简要创建过程

即将离职,闲来无事回顾下MVC的源码,到了Controller创建这里,由于流程有点复杂,鉴于自己记性不太好,索性就记录一下吧,方便日后参照. 首先看MvcHandler 1 public class MvcHandler : IHttpAsyncHandler, IHttpHandler, IRequiresSessionState 2 { 3 //... 4 private ControllerBuilder _controllerBuilder; 5 internal Controller

2. 基本请求controller的创建

(在上一节中创建好spring boot以后,就可以开始创建controller了,用于处理web请求) 1. 在spring boot的程序入口所在的 .java文件的同级目录,创建一个 controller.java文件 2. controller中代码如下 import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; impor

LoadRunner性能测试中Controller场景创建需注意的几点

在LR工具做性能测试中,最关键的一步是Controller场景的设计,因为场景的设计与测试用例的设计相关联,而测试用例的执行,直接影响最终的测试结果是怎么的,因此,我们每设计一种场景,就有可能是一个测试用例的执行(一个场景设计里面可以有多个脚本,场景计划方式可以按组方式,也可以按场景方式),如果场景的设计不正确或不合理,那也无谓在Analysis中结果分析了,对吧? 下面分享一下,在Controller设计场景时需要注意和理解的问题: 1.  在场景中持续时间设置将覆盖Vuser迭代设置.这意味

中小企业openstack私有云布署实践【8.2 身份认证keystone的API创建(办公网环境)】

其中一台controller上面加入环境变量,我选controller1,关注的是endpoint的名称不一样,其它创建的参数与生产环境一致 export OS_TOKEN=venicchina export OS_URL=http://controller:35357/v3 export OS_IDENTITY_API_VERSION=3 其中一台controller开始创建 openstack service create --name keystone --description "Ope

ASP.NET MVC进阶之路:深入理解Controller激活机制并使用Ioc容器创建对象

本文标题说是"深入理解Controller"其实有点“标题党”的味道了.本篇只会探讨"Controller"的激活机制,也就是如何创建Controller的并调用的.本篇不是讲解Controller底层相关知识,不过后期博文会对其进行介绍. 0X1 DefaultControllerFactory DefaultControllerFactory对象可以说是Controller创建激活的一个重要类,在默认情况下(这里的默认情况指没有向MVC指定负责创建Control

AngularJs(五)从Controller控制器谈谈$scope作用域

大纲 用于简单示例和简单应用的controller 应用 多个controller应用的作用域问题 controller继承作用域问题 Controller的创建 AngularJs controller使用无处不在,在里代码演示比较简单的创建工作. <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" ng-app="exampleApp"> <head> <

Ember——Ember 创建一个Object 对象

<!-创建好的completed模板-> <li {{action 'enterApp' appitem.id on='click'}}></li> *'enterApp'是要调用的函数名 *appitem.id 是要传给函数的参数ID名 *on='click' 是点击li触发的点击事件 一.定义一个命名空间 App = Ember.Application.create(); 二.创建一个对象 App.AppitemData=Ember.Object.extend();