ASP.NET MVC架構(第三部分): 把ViewData從控制器傳到視圖

來源:互聯網
上載者:User

【原文地址】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對象從控制器傳遞給你的視圖。使用這個強型別的方法有幾個好處:

  1. 避免使用字串來查詢對象,得到對你的控制器和視圖代碼的編譯時間檢查
  2. 避免需要在使用象C#這樣的強型別語言中明確轉換ViewData對象字典中的值
  3. 在你的視圖網頁的標識檔案以及後台代碼檔案中得到你的ViewData對象的自動代碼intellisense
  4. 可以使用代碼重構工具來協助自動化對整個應用和單元測試程式碼程式庫的改動

下面是一個強型別的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(測試驅動開發)的流程。在以後的貼子裡,我會對此做更深入的討論,以及討論你可以用來輕鬆測試代碼的最佳實務。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.