随笔 - 289  文章 - 1  评论 - 2716  阅读 - 195万

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
 

posted on   min.jiang  阅读(3413)  评论(2编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
< 2009年8月 >
26 27 28 29 30 31 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

点击右上角即可分享
微信分享提示