zoukankan      html  css  js  c++  java
  • mvc源码解析(6)获取ControllerType

       为什么要讲ControllerType?其实刚开始的时候并没有讲这个ControllerType的打算,但是在看mvc源码的时候,心里老是有个疙瘩,一直在琢磨ControllerType的含义,随着研究的深入才慢慢发现它的真正含义。ControllerType是出现在MvcHandler创建控制器的时候用到的:

        controller = factory.CreateController(RequestContext, controllerName);

    factory就是默认的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 = GetControllerType(requestContext, controllerName);
                IController controller = GetControllerInstance(requestContext, controllerType);
                return controller;
            }

    在创建controller之前,会根据当前的请求上下文和控制器的名称来获取controllerType,controllerType里面包含命名空间在内的Controller的具体信息。获取的ControllerType最终返回的是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 0:// no matching types                    

                          return null;

                    case 1:// single matching type                    

                          return matchingTypes.First();

                    default:// multiple matching types                    

                             throw CreateAmbiguousControllerException(route, controllerName, matchingTypes);            

         }        

    }

     看到红色的代码我们可以猜到是在由ControllerTypeCache建立的缓存中直接将匹配的matchingTypes取出来,我们直接看里面的方法实现吧:

    public ICollection<Type> GetControllerTypes(string controllerName, HashSet<string> namespaces) {            

            HashSet<Type> matchingTypes = new HashSet<Type>();

                ILookup<string, Type> nsLookup;            

                if (_cache.TryGetValue(controllerName, out nsLookup)) { 

                 // this friendly name was located in the cache, now cycle through namespaces                

                 if (namespaces != null) {                    

                   foreach (string requestedNamespace in namespaces) {                        

                         foreach (var targetNamespaceGrouping in nsLookup) {                            

                               if (IsNamespaceMatch(requestedNamespace, targetNamespaceGrouping.Key)) {                                

                                        matchingTypes.UnionWith(targetNamespaceGrouping);                            

                            }                        

                      }                    

                }                

           }                

        else { 

              // if the namespaces parameter is null, search *every* namespace                    

             foreach (var nsGroup in nsLookup) {                        

                  matchingTypes.UnionWith(nsGroup);                    

                           }                

                     }            

              }

           return matchingTypes;        

    }

     在这句代码中我也要注意一点:我们请求的controller所在的命名空间存储HashSet<String>中,而我们每次请求一次Action的时候,会将当前Action所在的Controller的名称和Controller所在的命名空间缓存在 ILookup<string, Type>中。我们来看红色代码IsNamespaceMatch方法,判断请求的controller所在的命名空间与目标命名空间是否一致,具体的方法实现如下:

    internal static bool IsNamespaceMatch(string requestedNamespace, string targetNamespace) {            

                  // degenerate cases            

                 if (requestedNamespace == null) {return false;}            

                 else if (requestedNamespace.Length == 0) {return true;}

                if (!requestedNamespace.EndsWith(".*", StringComparison.OrdinalIgnoreCase)) {

                       // looking for exact namespace match                

                      return String.Equals(requestedNamespace, targetNamespace, StringComparison.OrdinalIgnoreCase);}            

                else {

                       // looking for exact or sub-namespace match                

                       requestedNamespace = requestedNamespace.Substring(0, requestedNamespace.Length - ".*".Length);                

                       if (!targetNamespace.StartsWith(requestedNamespace, StringComparison.OrdinalIgnoreCase)) {return false;}

                       if (requestedNamespace.Length == targetNamespace.Length)

                           {

                                  // exact match  

                                  return true;                

                           }                

                         else if (targetNamespace[requestedNamespace.Length] == '.') {

                                       // good prefix match, e.g. requestedNamespace = "Foo.Bar" and targetNamespace = "Foo.Bar.Baz"                    

                                        return true;                

                              }                

                         else {                    

                                     // bad prefix match, e.g. requestedNamespace = "Foo.Bar" and targetNamespace = "Foo.Bar2"                    

                                     return false;                

                                }            

                        }        

                  }

    判断的具体逻辑我们不做详解,我们回到这么一句:

     ICollection<Type> matchingTypes = ControllerTypeCache.GetControllerTypes(controllerName, namespaces);

     获取到ControllerType之后,判断集合matchingTypes中找到的ControllerType的数量,如有一个则直接返回,如有多个匹配的项,则抛出异常。很显然,在同一个命名空间下不能有相同名称的Controller。这样我们就获取到了具体的ControllerType对象。

  • 相关阅读:
    2020春软件工程助教工作总结 第三周
    Zend Framework MVC的结构
    Zend_Cache的使用
    小油2018 win7旗舰版64位GHOST版的,安装telnet客户端时,提示:出现错误。并非所有的功能被成功更改。
    redis常用配置参数详解
    CentOS 7 源码编译安装 Redis
    Linux(CentOS)下设置nginx开机自动启动(2个办法)
    CST,CET,UTC,GMT,DST,Unix时间戳几种常见时间概述与关系(转)
    PHP_OS的常见值
    PHP_SELF、 SCRIPT_NAME、 REQUEST_URI区别
  • 原文地址:https://www.cnblogs.com/ghhlyy/p/2892246.html
Copyright © 2011-2022 走看看