2009-10-20 60 views
4

有人可以解释路径如何与MVC 2中的控制器相关联吗?目前,我在/Controllers/HomeController.cs和view/Home/Index.aspx中有一个控制器。ASP.NET MVC 2网址/路由,与控制器相关的视图如何?

我的路径登记方法看起来像这样:

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。这如何神奇地发生?当然,我错过了一些明显的东西。

然后

回答

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(); 
} 

然后默认视图引擎查找一个文件夹中称为指数(一样的动作)一个aspx文件名为“家园”(同作为控制器)在“Views”文件夹(约定)中。

如果它没有在其中找到,它还会在共享文件夹中查找索引页。

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目录中查找。

当谈到命名个别视图模板时,建议的指导是让视图模板与导致它呈现的操作方法共享同一个名称。例如,在我们的“索引”操作方法上方使用“索引”视图来呈现视图结果,而“细节”操作方法使用“细节”视图来呈现其结果。这可以很容易地快速查看哪个模板与每个操作关联。

当视图模板与在控制器上调用的操作方法名称相同时,开发人员不需要显式指定视图模板名称。我们可以将模型对象传递给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}"} 
); 

在这里,我明确指出我使用相册控制器和PhotoDetails操作,并将各种ID等传递给该操作。

+0

大部分是有道理的。但是,在第二个代码片段中传递给.MapRoute的默认对象引用了一个名为“Home”的控制器。我的控制器类被称为“HomeController”。我如何明确指定用于特定路由/ URL的控制器? – 2009-10-20 17:35:43

+0

您需要为这些路由添加明确的规则,并在默认参数中告诉它使用哪个Controller(不包括“Controller”后缀)。 – 2009-10-20 17:46:14

+0

谢谢 - 我会将此标记为已接受。但是,我是否正确理解在上面的示例中,“Albums”必须具有名为“AlbumsController”的相应控制器类? – 2009-10-20 17:50:24

2

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

+0

这解释了如何找到正确的视图,但是如何找到正确的控制器方法? – 2009-10-20 17:20:13

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

+0

这很奇怪。控制器类的名称必须与URL相关?如果我想使用同一个控制器来处理没有控制器名称的url,该怎么办? – 2009-10-20 17:27:45

+1

然后你在路由表中指定它:'routes.MapRoute(“MyRoute”,“someSpecialUrl/blabla”,new {controller =“Home”,action =“Index”,id =“”});'但你仍然必须指定要使用的控制器。 – 2009-10-20 17:30:38

+0

此外,与StringComparer.OrdinalIgnoreCase标志设置,这并不意味着该框架将无法区分HomeController和homecontroller? – 2009-10-20 17:30:46