ASP.NET MVC 2 urls / routes如何与控制器相关的视图?

时间:2009-10-20 16:56:57

标签: asp.net asp.net-mvc-2 asp.net-mvc-routing

有人可以解释一下MVC 2中路由器与控制器的关联方式吗?目前,我在/Controllers/HomeController.cs中有一个控制器和一个视图/Home/Index.aspx。

我的路线注册方法如下:

 public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
            routes.IgnoreRoute("{resource}.aspx/{*pathInfo}");
            routes.MapRoute(
               "Default",
                // Route name
               "{controller}/{action}/{id}",
                // URL with parameters
               new { controller = "Home", action = "Index", id = "" }
                // Parameter defaults
              );
        }

如果我请求URL:http://localhost/Home/Index,则HomeController.Index()正确处理请求。

但是,对于我的生活,我无法弄清楚url / Home / Index如何指向HomeController。据我所知,视图aspx没有引用HomeController,HomeController没有引用视图,路由表也没有明确提到HomeController。这神奇地发生了什么?当然,我错过了一些明显的东西。

然后

3 个答案:

答案 0 :(得分:6)

这是ASP.NET MVC中的约定。

使用DefaultControllerFactory时,此约定隐藏在内部密封类System.Web.Mvc.ControllerTypeCache内(Microsoft通常用于编写内部密封类)。在里面你会找到一个名为EnsureInitialized的方法,如下所示:

public void EnsureInitialized(IBuildManager buildManager)
{
    if (this._cache == null)
    {
        lock (this._lockObj)
        {
            if (this._cache == null)
            {
                this._cache = GetAllControllerTypes(buildManager).GroupBy<Type, string>(delegate (Type t) {
                    return t.Name.Substring(0, t.Name.Length - "Controller".Length);
                }, StringComparer.OrdinalIgnoreCase).ToDictionary<IGrouping<string, Type>, string, ILookup<string, Type>>(delegate (IGrouping<string, Type> g) {
                    return g.Key;
                }, delegate (IGrouping<string, Type> g) {
                    return g.ToLookup<Type, string>(t => t.Namespace ?? string.Empty, StringComparer.OrdinalIgnoreCase);
                }, StringComparer.OrdinalIgnoreCase);
            }
        }
    }
}

注意如何进行分组。因此,基本上,DefaultControllerFactory将查看实现Controller基类的类型的所有引用程序集,并从名称中删除“Controller”。

如果您真的想详细剖析ASP.NET MVC的管道,我建议您excellent article

答案 1 :(得分:5)

ASP.NET MVC附带的默认视图引擎适用于以下约定:

你有一个像这样的文件夹结构:

- Controllers\
|-  HomeController.cs
- Views\
|- Home\
|-- Index.aspx
|- Shared\

当请求进入并匹配RegisterRoutes方法中定义的路由时(请参阅URL routing之类的内容以获取更多信息),然后调用匹配的控制器:

routes.MapRoute(
  "Default", // Route name, allows you to call this route elsewhere
  "{controller}/{action}/{id}", // URL with parameters
  new { controller = "Home", action = "Index", id = "" } // Parameter defaults
  );

在默认路由中,您还指定了一个默认控制器(没有“Controller”后缀) - 路由引擎会自动将Controller添加到您的控制器名称 - 以及默认操作。

在您的控制器中,您可以调用简单方法:

public ActionResult Index(){
  return View();
}

默认视图引擎然后在“Views”文件夹(约定)中的名为“Home”的文件夹(与控制器相同)中查找名为Index的aspx文件(与操作相同)。

如果在那里找不到,那么它也会在共享文件夹中查找索引页。

来自ASP.NET MVC Nerd Dinner sample chapter

  

ASP.NET MVC应用程序在解析视图模板时默认使用基于约定的目录命名结构。这允许开发人员在从Controller类中引用视图时避免必须完全限定位置路径。默认情况下,ASP.NET MVC将在应用程序下的\Views\[ControllerName]\目录中查找视图模板文件。

     

\Views\Shared子目录提供了一种存储视图模板的方法,这些模板在应用程序中的多个控制器之间重复使用。当ASP.NET MVC尝试解析视图模板时,它将首先在\Views\[Controller]特定目录中进行检查,如果找不到视图模板,它将在\Views\Shared目录中查找。 / p>      

在命名单个视图模板时,建议的指导是使视图模板与导致其呈现的操作方法共享相同的名称。例如,在我们的“索引”操作方法上方使用“索引”视图来呈现视图结果,“详细信息”操作方法使用“详细信息”视图来呈现其结果。这样可以轻松快速查看与每个操作相关联的模板。

     

当视图模板与控制器上调用的操作方法同名时,开发人员不需要显式指定视图模板名称。我们可以只将模型对象传递给View()辅助方法(不指定视图名称),ASP.NET MVC会自动推断我们要使用磁盘上的\Views\[ControllerName]\[ActionName]视图模板来渲染它


编辑添加:

我设置的一些示例路由,显式设置控制器:

routes.MapRoute(
  "PhotoDetailsSlug",
  "Albums/{albumId}/{photoId}/{slug}",
  new {controller = "Albums", action = "PhotoDetails"},
  new {albumId = @"\d{1,4}", photoId = @"\d{1,8}"}
  );

这里我明确说明我正在使用Albums控制器和PhotoDetails操作,并将各种id传递给该操作。

答案 2 :(得分:2)

在操作索引中有一个语句return View()。返回空白视图时,DefaultViewEngine会在几个默认文件夹中搜索Controller方法的名称(特别是在FindView方法中)。其中一个是Views / Home目录,因为Home是控制器的名称。在那里它找到索引文件,并使用它来显示结果。