zoukankan      html  css  js  c++  java
  • asp.net mvc(五)

          我们在创建一个Controller时都会默认遵守这样的规定,名称+“Controller”,但我们在页面访问这个Controller时并不会写上后面的Controller字符,为什么系统能自动识别呢?这里我们也可以从Controller源码中得知。

          第一:Controller中的重要方法:CreateController,由它负责创建具体的Controller。这个方法根据用户传的controllerName(例如:Home)来取得实际的Controller的类型,其中用到这样的方法:this.GetControllerType(controllerName)。

    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");
        }
        
    this.RequestContext = requestContext;
        Type controllerType 
    = this.GetControllerType(controllerName);
        
    return this.GetControllerInstance(controllerType);
    }

      
          第二:GetControllerType方法体。主要是调用GetControllerTypeWithinNamespaces方法,根据controllerName和controller所对应的命名空间来取得实际Controller的类型。如果RequestContext.RouteData.DataTokens包含了Namespaces,则根据传递信息中的Namespaces和controllerName来取,否则按默认的命名空间和controllerName来取。

    protected internal virtual Type GetControllerType(string controllerName)
    {
        
    object obj2;
        Type controllerTypeWithinNamespaces;
        
    if (string.IsNullOrEmpty(controllerName))
        {
            
    throw new ArgumentException(MvcResources.Common_NullOrEmpty, "controllerName");
        }
        
    if ((this.RequestContext != null&& this.RequestContext.RouteData.DataTokens.TryGetValue("Namespaces"out obj2))
        {
            IEnumerable
    <string> collection = obj2 as IEnumerable<string>;
            
    if (collection != null)
            {
                HashSet
    <string> set = new HashSet<string>(collection, StringComparer.OrdinalIgnoreCase);
                controllerTypeWithinNamespaces 
    = this.GetControllerTypeWithinNamespaces(controllerName, set);
                
    if (controllerTypeWithinNamespaces != null)
                {
                    
    return controllerTypeWithinNamespaces;
                }
            }
        }
        HashSet
    <string> namespaces = new HashSet<string>(this.ControllerBuilder.DefaultNamespaces, StringComparer.OrdinalIgnoreCase);
        controllerTypeWithinNamespaces 
    = this.GetControllerTypeWithinNamespaces(controllerName, namespaces);
        
    if (controllerTypeWithinNamespaces != null)
        {
            
    return controllerTypeWithinNamespaces;
        }
        
    return this.GetControllerTypeWithinNamespaces(controllerName, null);
    }


            第三:接下来我们来看上面代码段用到的GetControllerTypeWithinNamespaces方法。这个方法用到了ControllerTypeCache,将在下面分析。可以看出,这个方法只返回所有符合条件的Type中的第一个类型,如果没有取到则返回空,如果查找到多个则返回第一个类型。

    private Type GetControllerTypeWithinNamespaces(string controllerName, HashSet<string> namespaces)
    {
        
    this.ControllerTypeCache.EnsureInitialized(this.BuildManager);
        IList
    <Type> controllerTypes = this.ControllerTypeCache.GetControllerTypes(controllerName, namespaces);
        
    switch (controllerTypes.Count)
        {
            
    case 0:
                
    return null;

            
    case 1:
                
    return controllerTypes[0];
        }
        StringBuilder builder 
    = new StringBuilder();
        
    foreach (Type type in controllerTypes)
        {
            builder.AppendLine();
            builder.Append(type.FullName);
        }
        
    throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, MvcResources.DefaultControllerFactory_ControllerNameAmbiguous, new object[] { controllerName, 

    builder }));
    }

     
          第四:ControllerTypeCache:它的作用是缓存了所有的控制器的类型信息。
                   ControllerTypeCache._cache 保存了所有载入程序集中的 Controller 类型;
                   EnsureInitialized方法:依据 "controllerName(不包含 Controller 字符串)"和 对应的Namespace 进行二级分组。
                   ControllerTypeCache.GetControllerTypes() 首先通过 controllerName 提取一级分组,然后用 namespaces 参数提取最终的类型数组。如果没有提供 Namespaces 则返回所有的同名 ControllerType。
                  分组示例:
    Home
      Namespace1
        Namespace1.HomeController
    GuestBoke
      Namespace1
        Namespace1.HomeController
      Namespace2
        Namespace2.HomeController 
          
                  ControllerTypeCache部分代码:

    Code

             

           上面的代码中允许出现不同命令空间但controllerName相同的Controller,例如默认asp.net mvc 工程在创建时已经创建了一下HomeController,我们在GuestBook.MVC.Controller工程中再创建一个同名的HomeController。然后修改下HomeController中的Index:

    public ActionResult Index()
            {
                ViewData[
    "Message"= "Welcome to ASP.NET MVC!";
                
    return RedirectToAction("About");
                
    //return View();
            }

          
          运行一下,程序并不会识别Contrller,错误信息如下:

    The controller name 'Home' is ambiguous between the following types:
    GuestBook.MVC.Controller.HomeController
    GuestBook.Web.Controllers.HomeController


          解决方案:选择任意一种都行。

              1:在路由规则中加了命名空间。

      routes.MapRoute(
                    
    "Default",                                              // Route name
                    "{controller}/{action}/{id}",                           // URL with parameters
                    new { controller = "Home", action = "Index", id = "" },  // Parameter defaults
                    new string[] { "GuestBook.MVC.Controller" }
                );

       
              2:ControllerBuilder.Current.DefaultNamespaces.Add("GuestBook.MVC.Controller");

          总结:本文分析了Controller与路由的关系。
          注:本文参考:http://www.rainsts.net/article.asp?id=777
     

  • 相关阅读:
    算法笔记_035:寻找最小的k个数(Java)
    (中级篇 NettyNIO编解码开发)第六章-编解码技术
    (入门篇 NettyNIO开发指南)第五章-分隔符和定长解码器使用
    (入门篇 NettyNIO开发指南)第四章-TIP黏包/拆包问题解决之道
    (入门篇 NettyNIO开发指南)第三章-Netty入门应用
    (基础篇 走进javaNIO)第二章-NIO入门
    (基础篇 走进javaNIO)第一章-java的i/o演进之路
    Apache Commons 工具类介绍及简单使用
    SimpleDateFormat使用和线程安全问题
    Calendar使用
  • 原文地址:https://www.cnblogs.com/ASPNET2008/p/1544612.html
Copyright © 2011-2022 走看看