• 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
     

  • 相关阅读:
    ORA-14404
    ORA-00845
    ORA-00054
    oracle-11g-配置dataguard
    ORACLE 11G 配置DG 报ORA-10458、ORA-01152、ORA-01110
    Python:if __name__ == '__main__'
    HDFS-Shell 文件操作
    HDFS 概述
    PL/SQL Developer
    CentOS7 图形化方式安装 Oracle 18c 单实例
  • 原文地址:https://www.cnblogs.com/ASPNET2008/p/1544612.html
Copyright © 2020-2023  润新知