2009-10-20 24 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