使用控制器和檢視來實作清單/詳細資料 UI
由 Microsoft 提供
這是免費的 "NerdDinner" 應用程式教學課程的第 4 個步驟,詳細介紹了如何使用 ASP.NET MVC 1 建置一個小型但完整的 Web 應用程式。
步驟 4 示範如何將控制器新增至應用程式,利用我們的模型為使用者提供 NerdDinner 網站上 Dinners 的資料清單/詳細資料瀏覽體驗。
如果使用 ASP.NET MVC 3,建議遵循 MVC 3 使用者入門或 MVC Music 市集教學課程。
NerdDinner 步驟 4:控制器和檢視
使用傳統 Web 架構 (傳統 ASP、PHP、ASP.NET Web Form 等) 時,傳入 URL 通常會對應至磁碟上的檔案。 例如:對 “/Products.aspx” 或 “/Products.php” 等 URL 的要求可能會由 “Products.aspx” 或 “Products.php” 檔案處理。
Web 架構會以稍微不同的方式將 URL 對應至伺服器程式碼。 它們不是將傳入的 URL 對應到檔案,而是對應到類別上的方法。 這些類別稱為 [控制器],負責處理傳入的 HTTP 要求、處理使用者輸入、擷取和儲存資料,以及判斷要傳送回用戶端的回應 (顯示 HTML、下載檔案、重新導向至不同的 URL 等等)。
既然我們已經為 NerdDinner 應用程式建置了基本模型,下一個步驟是將控制器新增至應用程式,以利用它為使用者提供網站上的 Dinners 資料清單/詳細資料瀏覽體驗。
新增 DinnersController 控制器
我們先以滑鼠右鍵按一下 Web 專案中的 [控制器] 資料夾,然後選取新增 ->控制器功能表命令 (您也可以輸入 Ctrl-M、Ctrl-C 來執行此命令):
這將會顯示 [新增控制器] 對話方塊:
我們將新控制器命名為 "DinnersController",然後按一下 [新增] 按鈕。 Visual Studio 接著會在 \Controllers 目錄下新增 DinnersController.cs 檔案:
它也會在程式碼編輯器中開啟新的 DinnersController 類別。
將 Index() 和 Details() 動作方法新增至 DinnersController 類別
我們要讓訪客使用我們的應用程式瀏覽即將推出的 Dinners 清單,並允許他們按一下清單中的任何 Dinner 以查看其具體的詳細資料。 為此,我們會從應用程式發佈下列 URL:
URL | 用途 |
---|---|
/Dinners/ | 顯示即將推出的 Dinners 的 HTML 清單 |
/Dinners/Details/[id] | 顯示 URL 內嵌之 "id" 參數所指出之特定 Dinner 的詳細資料,這會與資料庫中 Dinner 的 DinnerID 相符。 例如:/Dinners/Details/2 會顯示 HTML 頁面,其中包含 DinnerID 值為 2 之 Dinner 的詳細資料。 |
我們將藉由將兩個公用「動作方法」新增至 DinnersController 類別,以發佈這些 URL 的初始實作,如下所示:
public class DinnersController : Controller {
//
// HTTP-GET: /Dinners/
public void Index() {
Response.Write("<h1>Coming Soon: Dinners</h1>");
}
//
// HTTP-GET: /Dinners/Details/2
public void Details(int id) {
Response.Write("<h1>Details DinnerID: " + id + "</h1>");
}
}
然後,我們將執行 NerdDinner 應用程式,並使用瀏覽器來叫用它們。 輸入 "/Dinners/" URL 將導致 Index() 方法執行,並將傳回下列回應:
輸入 "/Dinners/Details/2" URL 會執行 Details() 方法,並傳回下列回應:
您可能想知道 - MVC ASP.NET 如何知道怎麼建立 DinnersController 類別並叫用這些方法? 為了理解這一點,讓我們快速了解路由的工作原理。
了解 ASP.NET MVC 路由
ASP.NET MVC 包含功能強大的 URL 路由引擎,可靈活控制 URL 對應至控制器類別的方式。 它可讓我們完全自訂 ASP.NET MVC 如何選擇要建立的控制器類別、要叫用哪一種方法,以及設定可以自動從 URL/查詢字串解析變數並將其作為參數傳遞給方法的不同方式。 它深具靈活性,完全最佳化網站的 SEO (搜尋引擎最佳化) 以及發佈我們所需的應用程式的任何 URL 結構。
根據預設,新的 ASP.NET MVC 專案隨附已註冊之預先設定 URL 路由規則集。 這可讓我們輕鬆開始使用應用程式,而無需明確設定任何內容。 預設路由規則註冊可以在我們專案的 [應用程式] 類別中找到,只需按兩下專案根目錄中的 “Global.asax” 檔案即可開啟:
預設 ASP.NET MVC 路由規則會註冊在此類別的 “RegisterRoutes” 方法中:
public void RegisterRoutes(RouteCollection routes) {
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL w/ params
new { controller="Home", action="Index",id="" } // Param defaults
);
}
上面呼叫的 "routes.MapRoute" 方法註冊了一個預設路由規則,該規則使用 URL 格式將傳入 URL 對應到控制器類別:"/{controller}/{action}/{id}" – 其中 “controller" 是名稱要具現化的控制器類別的名稱,"action" 是要在其上呼叫的公共方法的名稱,而 "id" 是內嵌在 URL 中的可選參數,可以作為參數傳遞給該方法。 傳遞至 "MapRoute()" 方法呼叫的第三個參數是一組預設值,用於 URL 中不存在的 controller/action/id 值 (Controller = “Home”, Action=“Index”, Id=“” ) 中。
以下資料表示範如何使用預設 “/{controllers}/{action}/{id}” 路由規則來對應各種 URL:
URL | 控制器類別 | 動作方法 | 參數已傳遞 |
---|---|---|---|
/Dinners/Details/2 | DinnersController | Details(id) | id=2 |
/Dinners/Edit/5 | DinnersController | Edit(id) | id=5 |
/Dinners/Create | DinnersController | Create() | N/A |
/Dinners | DinnersController | Index() | N/A |
/Home | HomeController | Index() | N/A |
/ | HomeController | Index() | N/A |
最後三個資料列會顯示使用的預設值 (Controller = Home, Action = Index, Id = “”)。 由於 "Index" 方法被註冊為預設動作名稱,如果未指定其他方法,則 "/Dinners" 和 "/Home" 這些 URL 會叫用其控制器類別上的 Index() 動作方法。 由於 "Home" 控制器被註冊為預設控制器,如果未指定其他控制器,則 "/" URL 會觸發 HomeController 的建立,並叫用其上的 Index() 動作方法。
如果您不喜歡這些預設 URL 路由規則,好消息是它們很容易變更,只要在上述 RegisterRoutes 方法內編輯這些規則即可。 不過,對於我們的 NerdDinner 應用程式,我們不會變更任何預設 URL 路由規則 ,而是將按原樣使用它們。
使用 DinnersController 中的 DinnerRepository
現在,讓我們將現有的 DinnersController 的 Index() 和 Details() 動作方法的實作,替換為使用我們模型的實作。
我們將使用稍早建置的 DinnerRepository 類別來實作行為。 我們將先新增一個引用 "NerdDinner.Models" 命名空間的 "using" 陳述式,然後將我們的 dinnerrepository 的執行個體宣告為 DinnerController 類別上的欄位。
我們將在本章後面介紹「相依性插入」的概念,並展示另一種方法,讓我們的控制器取得 DiningRepository 的參考,從而實現更好的單元測試,但現在我們只建立 DiningRepository 內嵌的執行個體。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using NerdDinner.Models;
namespace NerdDinner.Controllers {
public class DinnersController : Controller {
DinnerRepository dinnerRepository = new DinnerRepository();
//
// GET: /Dinners/
public void Index() {
var dinners = dinnerRepository.FindUpcomingDinners().ToList();
}
//
// GET: /Dinners/Details/2
public void Details(int id) {
Dinner dinner = dinnerRepository.GetDinner(id);
}
}
}
現在我們已經準備好使用擷取的資料模型物件來產生 HTML 回應。
搭配控制器使用檢視
雖然可以在我們的動作方法中撰寫程式碼來組合 HTML,然後使用 Response.Write() 協助程式方法將它傳回用戶端,但該方法會變得相當笨拙。 更好的方法是只在 DinnersController 動作方法中執行應用程式和資料邏輯,然後將轉譯 HTML 回應所需的資料傳遞給負責輸出 HTML 表示法的個別的 [檢視] 範本。 正如我們稍後將看到的,[檢視] 範本是一個文字檔案,通常包含 HTML 標記和內嵌轉譯程式碼的組合。
將控制器邏輯與檢視轉譯分開帶來了幾個很大的好處。 它特別是有助於在應用程式程式碼和 UI 格式化/轉譯程式碼之間,強制執行清晰的「關注點分離」。 這可讓您更輕鬆地將單元測試應用程式邏輯與 UI 轉譯邏輯隔離。 它使得以後修改 UI 轉譯範本變得更加容易,而無需變更應用程式程式碼。 開發人員和設計工具可以更輕鬆地在專案上共同作業。
我們可以透過將兩個動作方法的方法簽章從回傳類型 "void" 變更為傳回類型 "ActionResult" 來更新 DinnersController 類別,以指示我們想要使用檢視範本傳回 HTML UI 回應。 然後,我們可以在 Controller 基底類別上呼叫 View() 協助程式方法,以傳回 “ViewResult” 物件,如下所示:
public class DinnersController : Controller {
DinnerRepository dinnerRepository = new DinnerRepository();
//
// GET: /Dinners/
public ActionResult Index() {
var dinners = dinnerRepository.FindUpcomingDinners().ToList();
return View("Index", dinners);
}
//
// GET: /Dinners/Details/2
public ActionResult Details(int id) {
Dinner dinner = dinnerRepository.GetDinner(id);
if (dinner == null)
return View("NotFound");
else
return View("Details", dinner);
}
}
我們上述使用的 View() 協助程式方法的簽章如下所示:
View() 協助程式方法的第一個參數,是我們想要用來轉譯 HTML 回應的檢視範本檔案名稱。 第二個參數是模型物件,其中包含檢視範本為了轉譯 HTML 回應所需的資料。
在我們的 Index() 動作方法中,我們會呼叫 View() 協助程式方法,並指出我們要使用 [索引] 檢視範本轉譯 Dinners 的 HTML 清單。 我們向檢視範本傳遞一系列 Dinner 物件以從下列產生清單:
//
// GET: /Dinners/
public ActionResult Index() {
var dinners = dinnerRepository.FindUpcomingDinners().ToList();
return View("Index", dinners);
}
在我們的 Details() 動作方法中,我們會嘗試使用 URL 內提供的識別碼來擷取 Dinner 物件。 如果找到有效的 Dinner,我們呼叫 View() 協助程式方法,指出我們想要使用 [詳細資料] 檢視範本來轉譯擷取的 Dinner 物件。 如果要求無效的 Dinner,我們會轉譯有用的錯誤訊息,指出 Dinner 不存在使用 “NotFound” 檢視範本 (以及只採用範本名稱的 View() 協助程式方法多載版本):
//
// GET: /Dinners/Details/2
public ActionResult Details(int id) {
Dinner dinner = dinnerRepository.FindDinner(id);
if (dinner == null)
return View("NotFound");
else
return View("Details", dinner);
}
現在讓我們實作 "NotFound"、“Details” 和 “Index” 檢視範本。
實作 “NotFound” 檢視範本
我們先實作 "NotFound" 檢視範本,它會顯示一則易記的錯誤訊息,指出找不到要求的 Dinner。
我們將建立新的檢視範本,方法是將文字游標放在控制器動作方法內,然後按一下滑鼠右鍵並選擇 [新增檢視] 功能表命令 (您也可以輸入 Ctrl-M、Ctrl-V 來執行此命令):
這會顯示 [新增檢視] 對話方塊,如下所示。 根據預設,對話方塊會預先填入要建立的檢視名稱,以符合啟動對話方塊時游標所使用之動作方法的名稱 (在此案例中為 [詳細資料])。 因為我們要先實作 "NotFound" 範本,所以我們會覆寫此檢視名稱,並將它設定為 "NotFound":
當我們按一下 [新增] 按鈕時,Visual Studio 會在 “\Views\Dinners” 目錄中建立新的 "NotFound.aspx" 檢視範本 (如果目錄不存在也會建立):
它也會在程式碼編輯器中開啟新的 "NotFound.aspx" 檢視範本:
根據預設,檢視範本有兩個「內容區域」,我們可以在其中新增內容和程式碼。 第一個區域允許我們自訂傳回之 HTML 頁面的 [標題]。 第二個區域允許我們自訂傳回之 HTML 頁面的 [主要內容]。
若要實作 "NotFound" 檢視範本,我們將新增一些基本內容:
<asp:Content ID="Title" ContentPlaceHolderID="TitleContent" runat="server">
Dinner Not Found
</asp:Content>
<asp:Content ID="Main" ContentPlaceHolderID="MainContent" runat="server">
<h2>Dinner Not Found</h2>
<p>Sorry - but the dinner you requested doesn't exist or was deleted.</p>
</asp:Content>
然後,我們可以在瀏覽器中試用。 若要這樣做,讓我們要求 "/Dinners/Details/9999" URL。 這會參考資料庫中目前不存在的 Dinner,並會導致 DinnersController.Details() 動作方法轉譯我們的 “NotFound” 檢視範本:
在上面的螢幕擷取畫面中,您會注意到我們的基本檢視範本繼承了一堆圍繞螢幕上主要內容的 HTML。 這是因為我們的檢視範本使用 [主版頁面] 範本,可將一致的版面配置套用至網站上的所有檢視。 我們將在本教學課程的稍後部分討論主版頁面的運作方式。
實作 [詳細資料] 檢視範本
現在,讓我們實作 [詳細資料] 檢視範本, 這會為單一 Dinner 模型產生 HTML。
我們將文字游標放在 [詳細資料] 動作方法內,然後按一下滑鼠右鍵並選擇 [新增檢視] 功能表命令 (或按 Ctrl-M、Ctrl-V):
這會顯示 [新增檢視] 對話方塊。 我們將保留預設檢視名稱 ([詳細資料])。 我們也會在對話方塊中選取 [建立強型別檢視] 核取方塊,然後選取 (使用下拉式清單]) 從 [控制器] 傳遞至 [檢視] 的模型類型名稱。 在此檢視中,我們會傳遞 Dinner 物件 (此類型的完整名稱為:“NerdDinner.Models.Dinner”):
不同於先前的範本,我們選擇建立 [空白檢視],這次我們將選擇使用 [詳細資料] 範本自動 [建立] 檢視。 我們可以變更上述對話方塊中的 [檢視內容] 下拉式清單來指出這一點。
“Scaffolding” 會根據我們要傳遞的 Dinner 物件,產生詳細資料檢視範本的初始實作。 這為我們快速開始檢視範本實作提供了一種簡單的方法。
當我們按一下 [新增] 按鈕時,Visual Studio 會在 "\Views\Dinners" 目錄中建立一個新的 "Details.aspx" 檢視範本檔案:
它也會在程式碼編輯器中開啟新的 "Details.aspx" 檢視範本。 它會包含以 Dinner 模型為基礎的詳細資料檢視的初始建構實作。 建構引擎使用 .NET 反射來檢查傳遞給它的類別所公開的屬性,並根據找到的每種類型新增適當的內容:
<asp:Content ID="Title" ContentPlaceHolderID="TitleContent" runat="server">
Details
</asp:Content>
<asp:Content ID="Main" ContentPlaceHolderID="MainContent" runat="server">
<h2>Details</h2>
<fieldset>
<legend>Fields</legend>
<p>
DinnerID:
<%=Html.Encode(Model.DinnerID) %>
</p>
<p>
Title:
<%=Html.Encode(Model.Title) %>
</p>
<p>
EventDate:
<%= Html.Encode(String.Format("{0:g}", Model.EventDate)) %>
</p>
<p>
Description:
<%=Html.Encode(Model.Description) %>
</p>
<p>
HostedBy:
<%=Html.Encode(Model.HostedBy) %>
</p>
<p>
ContactPhone:
<%=Html.Encode(Model.ContactPhone) %>
</p>
<p>
Address:
<%=Html.Encode(Model.Address) %>
</p>
<p>
Country:
<%=Html.Encode(Model.Country) %>
</p>
<p>
Latitude:
<%= Html.Encode(String.Format("{0:F}",Model.Latitude)) %>
</p>
<p>
Longitude:
<%= Html.Encode(String.Format("{0:F}",Model.Longitude)) %>
</p>
</fieldset>
<p>
<%=Html.ActionLink("Edit","Edit", new { id=Model.DinnerID }) %>|
<%=Html.ActionLink("Back to List", "Index") %>
</p>
</asp:Content>
我們可以要求 "/Dinners/Details/1" URL 查看瀏覽器中此 [詳細資料] 建構實作的外觀。 使用此 URL 將顯示我們第一次建立資料庫時手動新增到資料庫中的 Dinners 之一:
這使我們能夠快速啟動並執行,並為我們提供了 Details.aspx 檢視的初始實作。 然後我們可以對其進行調整以自訂我們滿意的 UI。
當我們更仔細地查看 Details.aspx 範本時,將會發現它包含靜態 HTML 以及內嵌的轉譯程式碼。 當檢視範本轉譯時,<% % > 程式碼片段會執行程式碼,而 <%= %> 程式碼片段會執行包含在其中的程式碼,然後將結果轉譯至範本的輸出串流。
我們可以在 [檢視] 中撰寫程式碼,以存取使用強型別 [模型] 屬性從控制器傳遞的 [Dinner] 模型物件。 Visual Studio 提供我們在編輯器中存取此 [模型] 屬性時的完整程式碼 intellisense:
讓我們進行一些調整,使最終的 [詳細資料] 檢視範本的原始程式碼如下所示:
<asp:Content ID="Title" ContentPlaceHolderID="TitleContent" runat="server">
Dinner: <%=Html.Encode(Model.Title) %>
</asp:Content>
<asp:Content ID="Main" ContentPlaceHolderID="MainContent" runat="server">
<h2><%=Html.Encode(Model.Title) %></h2>
<p>
<strong>When:</strong>
<%=Model.EventDate.ToShortDateString() %>
<strong>@</strong>
<%=Model.EventDate.ToShortTimeString() %>
</p>
<p>
<strong>Where:</strong>
<%=Html.Encode(Model.Address) %>,
<%=Html.Encode(Model.Country) %>
</p>
<p>
<strong>Description:</strong>
<%=Html.Encode(Model.Description) %>
</p>
<p>
<strong>Organizer:</strong>
<%=Html.Encode(Model.HostedBy) %>
(<%=Html.Encode(Model.ContactPhone) %>)
</p>
<%= Html.ActionLink("Edit Dinner", "Edit", new { id=Model.DinnerID })%> |
<%= Html.ActionLink("Delete Dinner","Delete", new { id=Model.DinnerID})%>
</asp:Content>
當我們再次存取 "/Dinners/Details/1" URL 時,它現在會轉譯如下:
實作 [索引] 檢視範本
現在,讓我們實作 [索引] 檢視範本, 這將產生即將推出的 Dinners 清單。 為此,我們將文字游標放在 [索引] 動作方法內,然後按一下滑鼠右鍵並選擇 [新增檢視] 功能表命令 (或按 Ctrl-M、Ctrl-V)。
在 [新增檢視] 對話方塊中,我們會保留名為 [索引] 的檢視範本,然後選取 [建立強型別檢視] 核取方塊。 這次,我們將選擇自動產生 [清單] 檢視範本,然後選取 "NerdDinner.Models.Dinner" 作為傳遞至檢視的模型類型 (因為我們已指示我們正在建立 [清單] Scaffold,因此 [新增檢視] 對話方塊會假設我們正在將一連串的 Dinner 物件從 [控制器] 傳遞至 [檢視]):
當我們按一下 [新增] 按鈕時,Visual Studio 會在 "\Views\Dinners" 目錄中建立一個新的 "Index.aspx" 檢視範本檔案。 它會在其中「建構」初始實作,提供我們傳遞至檢視之 Dinners 的 HTML 資料表清單。
當我們執行應用程式並存取 "Dinners/" URL 時,它會轉譯我們的 Dinners 清單,如下所示:
上述資料表解決方案提供我們 Dinner 資料的格線式配置,這並不完全是我們想要的以消費者為導向的 Dinner 清單。 我們可以更新 Index.aspx 檢視範本,並修改它以列出較少的資料行,並使用 <ul> 元素來轉譯它們,而不是使用下列程式碼的資料表:
<asp:Content ID="Main" ContentPlaceHolderID="MainContent" runat="server">
<h2>Upcoming Dinners</h2>
<ul>
<% foreach (var dinner in Model) { %>
<li>
<%=Html.Encode(dinner.Title) %>
on
<%=Html.Encode(dinner.EventDate.ToShortDateString())%>
@
<%=Html.Encode(dinner.EventDate.ToShortTimeString())%>
</li>
<% } %>
</ul>
</asp:Content>
因為我們循環處理模型中的每個 Dinner,所以在上述 foreach 陳述式中使用 "var" 關鍵字。 那些不熟悉 C# 3.0 的人可能會認為使用 "var" 表示 Dinner 物件是晚期繫結。 相反地,這表示編譯程式會針對強型別的 [模型] 屬性使用類型推斷 (其類型為 “IEnumerable<Dinner>”),並將本機 “dinner” 變數編譯為 Dinner 類型,這表示我們在程式碼區塊內取得完整的 Intellisense 和編譯時間檢查:
當我們在瀏覽器中的 /Dinners URL 上叫用重新整理時,更新後的檢視現在如下所示:
這看起來好多了, 但仍然不完全。 我們最後一個步驟是讓終端使用者按一下清單中的個別 Dinners,並查看其詳細資料。 我們將透過轉譯 HTML 超連結元素來實現這一點,這些超連結元素連結到我們的 DinnersController上的 [詳細資料] 動作方法。
我們可以透過下列兩種方式之一,在 [索引] 檢視中產生這些超連結。 第一種是手動建立 HTML <a> 元素,如下所示,我們在 <a> HTML 元素中嵌入 <% %> 區塊:
我們可以使用的替代方法是利用 ASP.NET MVC 內的內建 "Html.ActionLink()" 協助程式方法,以支援以程式設計方式建立 HTML <a> 元素,以連結至 [控制器] 上的另一個動作方法:
<%= Html.ActionLink(dinner.Title, "Details", new { id=dinner.DinnerID }) %>
Html.ActionLink() 協助程式方法的第一個參數,是要顯示的連結文字 (在此案例中為 dinner 的標題),第二個參數是我們想要產生連結的 [控制器] 動作名稱 (在此案例中為 [詳細資料] 方法),而第三個參數是一組要傳送至動作的參數 (實作為具有屬性名稱/值的匿名類型)。 在此案例中,我們會指定我們想要連結之 dinner 的 “id” 參數,而且因為 ASP.NET MVC 中的預設 URL 路由規則是 “{Controller}/{Action}/{id}”,所以 Html.ActionLink() 協助程式方法會產生下列輸出:
<a href="/Dinners/Details/1">.NET Futures</a>
針對我們的 Index.aspx 檢視,我們將使用 Html.ActionLink() 協助程式方法,並將清單中的每個 dinner 連結到對應的詳細資料 URL:
<asp:Content ID="Title" ContentPlaceHolderID="TitleContent" runat="server">
Upcoming Dinners
</asp:Content>
<asp:Content ID="Main" ContentPlaceHolderID="MainContent" runat="server">
<h2>Upcoming Dinners</h2>
<ul>
<% foreach (var dinner in Model) { %>
<li>
<%=Html.ActionLink(dinner.Title, "Details", new { id=dinner.DinnerID }) %>
on
<%=Html.Encode(dinner.EventDate.ToShortDateString())%>
@
<%=Html.Encode(dinner.EventDate.ToShortTimeString())%>
</li>
<% } %>
</ul>
</asp:Content>
現在,當我們點擊 /Dinners URL 時,會顯示如下 dinner 清單:
當我們按一下清單中的任一個 Dinners 時,我們將瀏覽以查看其詳細資料:
以慣例為基礎的命名和 \Views 目錄結構
在預設情況下,ASP.NET MVC 應用程式在解析檢視範本時,會使用慣例型目錄命名結構。 這可讓開發人員避免在從 [控制器] 類別中參考檢視時,必須完全限定位置路徑。 根據預設,ASP.NET MVC 會在應用程式下方的 *\Views[ControllerName]* 目錄中尋找檢視範本檔案。
例如,我們一直在處理 DinnersController 類別,明確參考三個檢視範本:“Index”、“Details” 和 “NotFound”。 ASP.NET MVC 預設會在應用程式根目錄下的 \Views\Dinners 目錄中尋找這些檢視:
請注意上面的專案中目前存在三個控制器類別 (DinnersController、HomeController 和 AccountController - 最後兩個是我們建立專案時預設新增的),並且 \Views 中有三個子目錄 (每個控制器一個) 目錄。
從 Home 和 Accounts 控制器參考的檢視會自動從個別的 \Views\Home 和 \Views\Account 目錄解析其檢視範本。 \Views\Shared 子目錄提供了一種儲存檢視範本的方法,這些範本可以在應用程式內的多個控制器之間重複使用。 ASP.NET MVC 嘗試解析檢視範本時,它會先在 \Views[Controller] 特定目錄內檢查,如果找不到檢視範本,則會在 \Views\Shared 目錄中查看該範本。
在命名個別檢視範本時,建議的指導是讓檢視範本與導致其呈現的動作方法共用相同的名稱。 例如,上述 [索引] 動作方法使用 [索引] 檢視來轉譯檢視結果,而 [詳細資料] 動作方法則使用 [詳細資料] 檢視來轉譯其結果。 這可讓您輕鬆地快速查看與每個動作相關聯的範本。
當檢視範本的名稱與控制器上叫用的動作方法相同時,開發人員不需要明確指定檢視範本名稱。 我們可以改為將模型物件傳遞至 "View()" 協助程式方法 (而不指定檢視名稱),ASP.NET MVC 會自動推斷我們想要在磁碟上使用 \Views[ControllerName][ActionName] 檢視範本來轉譯它。
這可讓我們稍微清除控制器程式碼,並避免在程式碼中重複名稱兩次:
public class DinnersController : Controller {
DinnerRepository dinnerRepository = new DinnerRepository();
//
// GET: /Dinners/
public ActionResult Index() {
var dinners = dinnerRepository.FindUpcomingDinners().ToList();
return View(dinners);
}
//
// GET: /Dinners/Details/2
public ActionResult Details(int id) {
Dinner dinner = dinnerRepository.GetDinner(id);
if (dinner == null)
return View("NotFound");
else
return View(dinner);
}
}
上述的程式碼是網站實作良好的 Dinner 清單/詳細資料體驗所需的全部內容。
後續步驟
我們現在已經建置了良好的 Dinner 瀏覽體驗。
現在讓我們啟用 CRUD (建立、讀取、更新、刪除) 資料表單編輯支援。