此篇通過創(chuàng)建一個電子商務網(wǎng)站,討論ASP.NET MVC框架下控制器是如何與視圖做交互的。
AD:51CTO 網(wǎng)+ 第十二期沙龍:大話數(shù)據(jù)之美_如何用數(shù)據(jù)驅動用戶體驗
這個系列的第一篇建造了一個簡單的電子商務產品列表/瀏覽網(wǎng)站。它討論了MVC后面的高層次的概念,示范了如何從頭創(chuàng)建一個新的asp.net mvc項目,實現(xiàn)和測試這個電子商務產品列表功能。系列的第二篇對asp.net mvc框架的URL路徑選擇(routing)架構做了深入探討,討論了它的工作原理以及你如何使用它來處理更高級的URL路徑選擇場景。
此篇,將討論控制器是如何與視圖做交互的,具體來說,我將討論你可以把數(shù)據(jù)從控制器傳到視圖以顯示返回到客戶端的回復的各種方式。
第一部分的扼要簡述
在這個系列的第一部分,我們創(chuàng)建了一個電子商務網(wǎng)站,實現(xiàn)了基本的產品列表/瀏覽支持。我們是用asp.net mvc框架實現(xiàn)這個網(wǎng)站的,這個方法會很自然地將代碼結構化為獨特的控制器,模型和視圖組件。
當瀏覽器向我們的網(wǎng)站發(fā)送一個HTTP請求時,asp.net mvc框架將使用它的URL路徑選擇引擎,把進來的請求映射到一個控制器上的action方法來處理它。在基于MVC的應用中的控制器負責處理進來的請求,處理用戶輸入和交互,執(zhí)行基于這些輸入和交互的應用邏輯(獲取或更新存儲在數(shù)據(jù)庫中的模型數(shù)據(jù)等等)。
到生成返回到客戶端的HTML回復的時候,控制器一般是與“視圖”組件合作,這些視圖組件是以獨立于控制器的單獨的類或模板的形式實現(xiàn)的,其目的是完全注重于封裝顯示邏輯。
視圖不應該含有任何應用邏輯或數(shù)據(jù)庫訪問代碼,所有的應用/數(shù)據(jù)邏輯應該由控制器類來處理。這么劃分的動機是幫助強制你的應用/數(shù)據(jù)邏輯與界面生成代碼間的清晰分離。同時這也方便你獨立于你的界面顯示邏輯來單元測試你的應用/數(shù)據(jù)邏輯。
視圖應該只使用從控制器傳過來的特定于視圖的數(shù)據(jù)來生成輸出。在asp.net mvc框架中,我們稱這個特定于視圖的數(shù)據(jù)為“ViewData”。這個博客的其他部分將討論你可以用來將ViewData從控制器傳遞給視圖來生成顯示的一些不同方法。
一個簡單的產品列表場景
為幫助說明我們可以用來把ViewData從控制器傳遞給視圖的一些技術,讓我們來建造一個簡單的產品列表網(wǎng)頁:
我們將用一個CategoryID整數(shù)來過濾我們想要顯示在頁面上的產品。注意上面我們是如何把CategoryID嵌在URL中的(例如,Products/Category/2 或 /Products/Category/4 )。
然后,我們的產品列表網(wǎng)頁顯示了2個不同的動態(tài)內容元素。第一個元素是我們要顯示的分類的文本名稱(例如,Condiments-調味品),第二個元素是一個HTML < ul>< li/>< /ul> 產品名字列表。我在上面的屏幕截圖中對這2個元素用紅筆畫了圈。
在下面,我們將看一下我們可以使用的2個不同的方法來實現(xiàn)ProductsController類,這個類處理進來的請求,獲取處理請求所需的數(shù)據(jù),然后將這個數(shù)據(jù)傳給一個List視圖來顯示。我們要研究的第一個方法是用后期綁定的字典對象傳遞這個數(shù)據(jù),第二個方法則使用強類型類的方式來傳遞這個數(shù)據(jù)。
方法 1:使用 Controller.ViewData 字典來傳遞ViewData
Controller基類有個ViewData字典屬性,可以用來填充你要傳給視圖的數(shù)據(jù)。你使用鍵/值模式將對象加入 ViewData 字典。
下面是個ProductsController類,其中的Category action方法實現(xiàn)了我們上面的產品列表場景。注意,它是如何使用分類的ID參數(shù)來查詢該分類的文本名稱,以及獲取該分類中的產品列表的。它使用“CategoryName”和“Products”兩個鍵將這兩個數(shù)據(jù)存儲在Controller.ViewData 集合中:
然后,我們上面的Category action方法調用 RenderView("List") 來表示它要用哪個模板來做顯示。當你象這樣調用RenderView時,它會將ViewData字典傳給視圖,以顯示對應的回復。
實現(xiàn)我們的視圖
我們將使用居于我們項目的\Views\Products目錄下的List.aspx文件來實現(xiàn)我們的List視圖。這個 List.aspx 將繼承 \Views\Shared 文件夾中的Site.Master母版頁中的布局(在你創(chuàng)建一個新的視圖網(wǎng)頁時,你可以在 VS 2008 中,右擊,選擇添加新項->MVC視圖內容網(wǎng)頁來接連一個母版頁):
當我們使用MVC視圖內容網(wǎng)頁模板來創(chuàng)建List.aspx網(wǎng)頁時,它不是從通常的 System.Web.UI.Page 類繼承而來,而是從System.Web.Mvc.ViewPage 基類繼承而來(是現(xiàn)有的Page類的一個子類):
ViewPage基類提供一個ViewData字典屬性,我們可以在視圖網(wǎng)頁里訪問由控制器添加的數(shù)據(jù)對象。然后我們可以取出這些數(shù)據(jù)對象,使用它們來顯示HTML輸出,可以用服務器控件的方式,或者用 < %= %> 顯示代碼的方式。
使用服務器控件來實現(xiàn)我們的視圖
下面是一個如何使用現(xiàn)有的< asp:literal> 和 < asp:repeater>服務器控件來實現(xiàn)我們的HTML界面的例子:
我們可以用下面的后臺代碼類將 ViewData 綁定到這些控件之上(注意我們是如何使用ViewPage的ViewData字典來實現(xiàn)的 ):
注: 因為頁面上沒有 < form runat="server">,是不會輸出 view-state 的。上面的控件也不會自動生成任何ID值,這意味著你對輸出的HTML有完全的控制。
使用 < %= %> 代碼來實現(xiàn)我們的視圖
如果你更喜歡使用行內代碼來生成輸出的話,你可使用下面的 List.aspx 來實現(xiàn)跟上面完全一樣的結果:
注: 因為ViewData的類型是含有“objects”的字典,為了對它使用foreach語句,我們需要將ViewData["Products"]的類型轉換成 List< Product> 或者 IEnumerable< Product>。我在頁面上引用了System.Collections.Generic 和 MyStore.Models 命名空間 以避免輸入 List< T> 和 Product 類型的完整名稱。
注: 上面使用了“var”關鍵詞,這是VS 2008中新的 C# 和 VB “類型推斷”特性的一個例子(在這里閱讀我以前的相關貼子)。因為我們將ViewData["Products"] 轉換成了 List< Product>,我們在 List.aspx 文件中的 prduct 變量上得到了完整的intellisense:
這樣就使用ASP.NET MVC框架實現(xiàn)了一個電子商務網(wǎng)站。