【转】Scott_ASP.NET MVC框架(第三部分) 把ViewData从控制器传到视图
Scott的MVC框架系列,非常好的MVC學習資料。很適合初學者閱讀。做為一個系列轉載過來,純粹是為了學習方便。
文章轉自:Scott Guthrie 博客中文版
【原文地址】ASP.NET MVC Framework (Part 3): Passing ViewData from Controllers to Views
【原文發表日期】 Thursday, December 06, 2007 2:49 AM
【譯注】根據Scott Guthrie原文的回復,ASP.NET MVC框架的第一個CTP將于12月7日發布
過去的幾個星期內,我一直在寫著討論我們正在開發的新ASP.NET MVC框架的系列貼子。ASP.NET MVC框架是個你可以用來結構化你的ASP.NET web應用,使之擁有清晰的關注分離,方便你單元測試代碼和支持TDD流程的可選方法。
這個系列的第一篇建造了一個簡單的電子商務產品列表/瀏覽網站。它討論了MVC后面的高層次的概念,示范了如何從頭創建一個新的ASP.NET MVC項目,實現和測試這個電子商務產品列表功能。系列的第二篇對ASP.NET MVC框架的URL路徑選擇(routing)架構做了深入探討,討論了它的工作原理以及你如何使用它來處理更高級的URL路徑選擇場景。
在今天的帖子里,我將討論控制器是如何與視圖做交互的,具體來說,我將討論你可以把數據從控制器傳到視圖以顯示返回到客戶端的回復的各種方式。
第一部分的扼要簡述
在這個系列的第一部分,我們創建了一個電子商務網站,實現了基本的產品列表/瀏覽支持。我們是用ASP.NET MVC框架實現這個網站的,這個方法會很自然地將代碼結構化為獨特的控制器,模型和視圖組件。
當瀏覽器向我們的網站發送一個HTTP請求時,ASP.NET MVC框架將使用它的URL路徑選擇引擎,把進來的請求映射到一個控制器上的action方法來處理它。在基于MVC的應用中的控制器負責處理進來的請求,處理用戶輸入和交互,執行基于這些輸入和交互的應用邏輯(獲取或更新存儲在數據庫中的模型數據等等)。
到生成返回到客戶端的HTML回復的時候,控制器一般是與“視圖”組件合作,這些視圖組件是以獨立于控制器的單獨的類或模板的形式實現的,其目的是完全注重于封裝顯示邏輯。
視圖不應該含有任何應用邏輯或數據庫訪問代碼,所有的應用/數據邏輯應該由控制器類來處理。這么劃分的動機是幫助強制你的應用/數據邏輯與界面生成代碼間的清晰分離。同時這也方便你獨立于你的界面顯示邏輯來單元測試你的應用/數據邏輯。
視圖應該只使用從控制器傳過來的特定于視圖的數據來生成輸出。在ASP.NET MVC框架中,我們稱這個特定于視圖的數據為“ViewData”。這個博客的其他部分將討論你可以用來將ViewData從控制器傳遞給視圖來生成顯示的一些不同方法。
一個簡單的產品列表場景
為幫助說明我們可以用來把ViewData從控制器傳遞給視圖的一些技術,讓我們來建造一個簡單的產品列表網頁:
我們將用一個CategoryID整數來過濾我們想要顯示在頁面上的產品。注意上面我們是如何把CategoryID嵌在URL中的(例如,Products/Category/2 或 /Products/Category/4 )。
然后,我們的產品列表網頁顯示了2個不同的動態內容元素。第一個元素是我們要顯示的分類的文本名稱(例如,Condiments-調味品),第二個元素是一個HTML <ul><li/></ul> 產品名字列表。我在上面的屏幕截圖中對這2個元素用紅筆畫了圈。
在下面,我們將看一下我們可以使用的2個不同的方法來實現ProductsController類,這個類處理進來的請求,獲取處理請求所需的數據,然后將這個數據傳給一個List視圖來顯示。我們要研究的第一個方法是用后期綁定的字典對象傳遞這個數據,第二個方法則使用強類型類的方式來傳遞這個數據。
方法 1:使用 Controller.ViewData 字典來傳遞ViewData
Controller基類有個ViewData字典屬性,可以用來填充你要傳給視圖的數據。你使用鍵/值模式將對象加入 ViewData 字典。
下面是個ProductsController類,其中的Category action方法實現了我們上面的產品列表場景。注意,它是如何使用分類的ID參數來查詢該分類的文本名稱,以及獲取該分類中的產品列表的。它使用“CategoryName”和“Products”兩個鍵將這兩個數據存儲在Controller.ViewData 集合中:
?
然后,我們上面的Category action方法調用 RenderView("List") 來表示它要用哪個模板來做顯示。當你象這樣調用RenderView時,它會將ViewData字典傳給視圖,以顯示對應的回復。
實現我們的視圖
我們將使用居于我們項目的\Views\Products目錄下的List.aspx文件來實現我們的List視圖。這個 List.aspx 將繼承 \Views\Shared 文件夾中的Site.Master母版頁中的布局(在你創建一個新的視圖網頁時,你可以在 VS 2008 中,右擊,選擇添加新項->MVC視圖內容網頁來接連一個母版頁):
當我們使用MVC視圖內容網頁模板來創建List.aspx網頁時,它不是從通常的 System.Web.UI.Page 類繼承而來,而是從System.Web.Mvc.ViewPage 基類繼承而來(是現有的Page類的一個子類):
ViewPage基類提供一個ViewData字典屬性,我們可以在視圖網頁里訪問由控制器添加的數據對象。然后我們可以取出這些數據對象,使用它們來顯示HTML輸出,可以用服務器控件的方式,或者用 <%= %> 顯示代碼的方式。
使用服務器控件來實現我們的視圖
下面是一個如何使用現有的<asp:literal> 和 <asp:repeater>服務器控件來實現我們的HTML界面的例子:
我們可以用下面的后臺代碼類將 ViewData 綁定到這些控件之上(注意我們是如何使用ViewPage的ViewData字典來實現的 ):
注: 因為頁面上沒有 <form runat="server">,是不會輸出 view-state 的。上面的控件也不會自動生成任何ID值,這意味著你對輸出的HTML有完全的控制。
使用 <%= %> 代碼來實現我們的視圖
如果你更喜歡使用行內代碼來生成輸出的話,你可使用下面的 List.aspx 來實現跟上面完全一樣的結果:
注: 因為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:
方法 2:使用強類型類來傳遞ViewData
除了支持后期綁定的字典方法外,ASP.NET MVC框架還允許你把強類型的ViewData對象從控制器傳遞給你的視圖。使用這個強類型的方法有幾個好處:
下面是一個強類型的ProductsListViewData類,封裝了 List.aspx 視圖顯示我們的產品列表所需的數據,它含有 CategoryName 和 Products 屬性(是通過使用新的C#自動屬性支持來實現的):
然后我們可以更新我們的 ProductsController 實現來使用這個對象,把一個強類型的ViewData對象傳給我們的視圖:
注意上面,我們是如何通過 RenderView() 方法的一個額外的參數,把我們的強類型 ProductsListViewData 對象傳給View的。
把視圖的ViewData字典與強類型的ViewData對象一起使用
前面我們編寫的 List.aspx 視圖實現會繼續和我們更新過的 ProductsController 協作,不需改動代碼。這是因為,當把一個強類型的 ViewData 對象傳遞給繼承自 ViewPage 的視圖類時,ViewData 字典會自動使用反射對強類型的對象的屬性做查詢取值。所以我們象下面這樣的視圖中的代碼:
會自動使用反射來從強類型的 ProductsListViewData 對象中獲取 CategoryName 屬性,這個對象是我們在調用 RenderView 方法時傳入的。
使用ViewPage<T>基類來對ViewData強類型化
除了支持基于字典的ViewPage基類外,ASP.NET MVC框架中還發布有基于泛型的 ViewPage<T> 實現。如果你的視圖是從 ViewPage<T> 繼承而來,這里T表示是控制器傳給視圖的 ViewData 的類型,那么 ViewData 屬性就將是使用了這個T類的強類型屬性。
例如,我們可以更新我們的 List.aspx.cs 后臺代碼類,不是從ViewPage繼承來,而是繼承自 ViewPage<ProductsListViewData> :
這么做之后,頁面上的 ViewData 屬性將會從一個字典變成屬于 ProductsListViewData 類型。這意味著,我們現在可以不再使用基于字符串的字典來查閱獲取數據,而是可以使用強類型的屬性了:
然后,我們可以使用服務器控件的方法,或者 <%= %> 顯示的方法來生成基于這個ViewData的HTML。
使用服務器控件來實現 ViewPage<T>視圖
下面是一個例子,我們可以使用<asp:literal> 和 <asp:repeater>服務器控件來實現我們的HTML界面。這是我們使用繼承自 ViewPage 的 List.aspx 網頁時所使用的完全一樣的標識:
下面是相應的后臺代碼。注意,因為我們是從 ViewPage<ProductsListViewData> 繼承而來的,我們可以直接訪問它的屬性,而不要對任何東西做類型轉換(什么時候我們決定對其中一個屬性改名的話,我們還將得到重構工具的支持):
使用 <%= %> 代碼實現我們的 ViewPage<T> 視圖
如果你更喜歡使用行內代碼來生成輸出的話,你可以象下面這樣在 List.aspx 中達成跟上面一樣的結果:
使用 ViewPage<T> 方法,我們現在不再需要對 ViewData 使用字符串查閱了。更重要的是,注意上面,我們不再需要對任何屬性做類型轉換了,因為它們已經是強類型的。這意味著,我們可以編寫 foreach (var product in ViewData.Products) ,而不用對 Products 做類型轉換。我們還在循環中的 product 變量上得到了完整的intellisense:
結語
希望本貼子提供了關于控制器如何把數據傳遞給視圖以顯示返回到客戶端的回復的一些細節。你可以使用后期綁定的字典,或者使用強類型的方式來達成這個目的。
第一次試著建造MVC應用時,你很可能發現把應用控制器的邏輯和生成界面的代碼分離開來的概念有點怪。你大概要花上一段專門的時間來多建造些應用,你才會感到習慣,把自己的思路轉向到處理一個請求,執行所有的應用邏輯,把建造界面回復所需的 viewdata 包裝起來,然后交給單獨的一個視圖頁面去顯示的觀念上去。 重要事項:如果這個模型對你來說并不感覺舒服,那么別用它,MVC的方法純粹是可選的,我們并不認為這是每個人都想要用的東西。
但這個劃分應用的好處以及其后的目標在于,它允許你獨立于你的界面顯示代碼,來運行和測試你的應用和數據邏輯。這極大地方便你為你的應用開發全面的單元測試,以及在建造應用時使用TDD(測試驅動開發)的流程。在以后的貼子里,我會對此做更深入的討論,以及討論你可以用來輕松測試代碼的最佳實踐。
希望本文對你有所幫助,
Scott
轉載于:https://www.cnblogs.com/tenghoo/archive/2009/03/11/1408457.html
總結
以上是生活随笔為你收集整理的【转】Scott_ASP.NET MVC框架(第三部分) 把ViewData从控制器传到视图的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: FMS3系列(二):创建可交互的FMS连
- 下一篇: 开发工具(三)