ASP.NET MVC架構(第一部分)

來源:互聯網
上載者:User

【原文地址】ASP.NET MVC Framework (Part 1)
【原文發表日期】 Tuesday, November 13, 2007 3:45 AM

兩個星期前, 我在部落格裡討論了ASP.NET的一個新MVC(模型、視圖,控制器)架構,我們將在不久的將來作為一個可選功能來支援。該架構提供了一個結構化的模型,來加強應用中的清晰關注分離,方便你單元測試代碼和支援TDD流程。它還提供了對你在應用中發布的URL的更多的控制,也可以對從中輸出的HTML提供更多的控制。

之後,我回答了來自迫切想瞭解更多詳情的很多人的很多問題。鑒於如此高的興趣,我覺得,寫幾個貼子更詳細地描述如何使用這個架構,也許更有意義些。這是我將在以後幾個星期裡要撰寫的相關貼子的第一個。

一個簡單的電子商務店面應用

我將使用一個簡單的電子商務商店應用來示範ASP.NET MVC架構的工作原理。在今天的貼子裡,我將實現一個產品列單,以及相關的瀏覽應用情境。

具體來說,我們將建造一個網上商店,允許使用者在訪問該網站上的/Products/Categories網址時 瀏覽產品分類列表:

當使用者點擊上面網頁上的產品分類連結時,他們將轉到一個產品分類列表URL /Products/List/CategoryName上,該頁面列出了指定分類中的還在銷售的產品:

當使用者點擊個別的產品時,他們將轉到產品細節URL /Products/Detail/ProductID上,這個網頁將顯示使用者選定的產品的更多細節:

我們將使用新的ASP.NET MVC架構來實現上述的所有功能。這將會允許我們在應用的不同組件間保持“清晰的關注分離”,允許我們更輕易地整合單元測試和測試驅動的開發。

建立一個新的ASP.NET MVC應用

ASP.NET MVC架構套件含一個Visual Studio項目模板,方便你建立新的MVC web應用。選擇檔案->新項目菜單,選擇“ASP.NET MVC Web 應用程式”模板,用它建立一個新web應用。

在預設情形下,當你使用該選項產生一個新應用時,Visual Studio 將為你建立一個新的解決方案,然後往裡面加2個項目。第一個項目是web項目,在其中你實現你的web應用的功能。第二個項目是個測試專案,你可以在其中編寫單元測試,來測試你的應用代碼:

你可以在ASP.NET MVC 架構中使用任何單元測試架構,包括NUnit, MBUnit, MSTest, XUnit以及其他的架構。VS 2008專業版現在包含了對MSTest的內建測試專案的支援(VS 2005版本的MSTest要求你擁有Visual Studio Team System版本才能使用),當你使用VS 2008時,預設的ASP.NET MVC 項目模組自動產生這樣的測試專案。

我們還將發布可用以NUnit, MBUnit 和其他單元測試架構的項目模板,所以,如果你更喜歡那些架構的話,你可以輕鬆地一次點擊即產生你的應用和可以馬上使用的相應的測試專案。

理解項目的目錄結構

ASP.NET MVC 應用的預設目錄結構有三個頂層目錄:

  • /Controllers
  • /Models
  • /Views

你大概可以猜出來,我們建議把控制器類置於 /Controllers 目錄之中,你的資料模型類置於/Models目錄之中,你的視圖模板置於 /Views 目錄之中。

雖然ASP.NET MVC架構並不強迫你總是使用這個結構,但預設的項目模板使用這個模式,我們也把它作為結構化應用的一種比較容易的方式向你推薦。除非你有好的理由使用另外的檔案布局,我建議你使用這個預設模式。

把URL映射到Controller類

在大多數web架構(ASP, PHP, JSP, ASP.NET WebForms等等)裡,到來的URL一般都映射到儲存在硬碟上的模板檔案。譬如,"/Products.aspx"或者 "/Products.php" URL一般都在硬碟上有個對應的Products.aspx 或Products.php 模板檔案來處理請求。當一個web應用的http請求進入web伺服器時,web架構運行由硬碟上的模板檔案指定的代碼,然後這代碼負責處理該請求。很多時候,這代碼使用Products.aspx 或 Products.php檔案中的HTML 標識來協助產生返回用戶端的響應。

MVC架構一般以不同的方式把URL映射到伺服器代碼上。它不是將URL映射到硬碟上的模板檔案,而是直接把URL映射到代碼類上。這些類稱為 “Controllers(控制器)”,它們負責處理到來的請求,處理使用者輸入和互動,執行基於輸入和互動的相應的應用和資料邏輯。然後,一個 Controller類一般會調用單獨的“視圖”組件,該組件負責產生請求的實際的HTML輸出。

ASP.NET MVC架構套件括一個非常強大的URL映射引擎,在如何把URL映射到Controller類方面,該引擎提供了很多靈活性。你可以使用它來輕鬆地設定 routing(直接選取,路由)規則,然後ASP.NET會根據這些規則,對進來的URL進行評估,選出一個Controller來運行。然後你也可以讓routing引擎自動分析出你在URL裡定義的變數,讓ASP.NET自動把這些變數作為參數傳給你的Controller。我將在這個系列將來的一個貼子裡,討論涉及URL routing引擎的比較進階的情境。

映射到控制器類的預設ASP.NET MVC URL Routing規則

在預設情形下,ASP.NET MVC項目有一套預先配置好的URL routing規則,這些規則允許你不用配置什麼,就可以輕鬆地上路。這樣,使用一套預設的基於名稱的URL映射約定,你就可以開始編寫代碼了,這些約定是在Global.asax檔案(由Visual Studio中新的ASP.NET MVC項目模板產生的)中的ASP.NET Application類中聲明的。

預設的命名規範是這樣的:把進來的HTTP請求的URL路徑的開頭部分,譬如 /Products/,映射到一個類,該類的名稱遵循UrlPathController的模式,譬如在預設情形下,一個以/Products/開頭的URL 會被映射到名為ProductsController的類上。

為建造我們的電子商務產品瀏覽功能,我們將在我們的項目中加一個新的“ProductsController”類 (你可以使用Visual Studio中的“添加新項”菜單從模板中輕鬆地建立一個Controller類):

我們的ProductsController是從System.Web.MVC.Controller 基類繼承而來,從這個基類繼承而來並不是必需的,但它含有一些我們以後可以使用的非常有用的輔助方法和功能:

在項目中定義這個ProductsController類之後,在預設情形下,ASP.NET MVC 架構就會使用它來處理所有到來的以"/Products/"開頭的URL的應用請求。這意味著,它會自動被調用來處理我們將在我們的網上商店應用中開啟的 "/Products/Categories", "/Products/List/Beverages", 和 "/Products/Detail/3" 等URL。

在將來的貼子裡,我們還將添加一個ShoppingCartController(以允許使用者管理他們的購物車)以及 AccountController (允許使用者在網站上建立新的成員帳號,實現登入和退出等功能)。在向我們的項目裡添加這2個新的控制器類之後,以/ShoppingCart/ 和 /Account/開頭的URL就會自動地導向到這些類做處理。

註:ASP.NET MVC架構並不要求你總是使用這個命名規範模式。我們的應用預設使用這個模式的唯一原因是因為在我們使用Visual Studio建立新的ASP.NET MVC項目時,有一個配置了這個模式的映射規則被自動地添加到了我們的ASP.NET Application 類中。如果你不喜歡這個規則,或者想使用另外的URL映射模式來對它進行定製,那麼就到Global.asax中的ASP.NET Application類中做改動。我會在以後的一個貼子討論該怎麼做,到時我也會展示一些URL routing引擎允許的一些非常酷的情境。

理解控制器的Action方法

既然我們已經在項目裡建立了一個ProductsController類,我們可以開始添加邏輯來處理來到應用的"/Products/" URL了。

在本貼子的前面定義我們的電子商務店面用例時,我說過我們將在網站上實現3個情境:1) 瀏覽所有的產品分類, 2) 列出特定分類裡的產品, 和 3) 顯示特定產品的細節。我們將使用下列這些SEO友好的URL來處理這三個情境:

URL格式 行為 URL例子
/Products/Categories 瀏覽所有的產品分類 /Products/Categories
/Products/List/Category 列出特定分類裡的產品 /Products/List/Beverages
/Products/Detail/ProductID 顯示特定產品的細節 /Products/Detail/34

我們可以用幾種方式在ProductsController類中編寫代碼來處理這三類到來的URL。一種方式是,覆蓋Controller基類中的 “Execute”方法,手工編寫我們自己的 if/else/切換邏輯,對照使用者請求的URL,然後執行適當的邏輯來處理這個請求。

但一種容易得多的方式是,使用MVC架構中內建的功能,該功能允許我們在我們的控制器中定義“action方法”,然後由Controller基類根據我們應用使用的URL routing規則來自動調用適當的action方法來執行。

譬如,我們可以往我們的ProductsController類裡添加如下所示的三個控制器action方法,來處理上述的三個電子商務URL情境:

在項目建立時預設配置的URL routing規則會把緊隨控制器名稱之後的子路徑當作請求的action名稱來對待。所以,如果我們收到一個/Products/Categories 的URL請求,routing規則會把“Categories”作為一個action的名稱來對待,Categories() 方法就會被調用來處理這個請求。如果我們收到的是 /Products/Detail/5 URL請求,routing規則就會把“Detail"”當中action的名稱,Detail() 方法就會被調用來處理請求,等等。

註:ASP.NET MVC架構並不要求你總是使用這個action命名規範模式。如果你想使用不同的URL映射模式,到 Global.asax檔案中的ASP.NET Application類去做改動。

把URL參數映射到Controller的Action方法上

在Controller類中的action方法中可以用幾個方法訪問URL中的參數值。

Controller基類呈現了可以使用的Request 和Response對象。這些對象跟ASP.NET中你已經熟悉的HttpRequest/HttpResponse對象擁有完全一樣的API結構。一個非常重要的區別是,這些對象現在是基於介面(interface)的,而不是封閉的類。具體來說,MVC 架構將發布System.Web.IHttpRequest和System.Web.IHttpResponse介面。這些對象是基於的介面的好處是,現在非常容易mock(模仿)它們,這樣,就可以方便對控制器類的單元測試。在將來的部落格貼子裡,我將對此進行深入的討論。

下面是一個如何在ProductsController類的Detail action方法中使用Request API來手工擷取ID查詢字串值的例子:

ASP.NET MVC 架構還支援自動將進來的URL的參數值對應成action方法的參數。在預設情形下,如果你的action方法有個參數的話,MVC架構會檢查進來的請求的資料,看是否有個同樣名稱的對應的HTTP請求值。如果有的話,它會自動將其作為參數傳入你的action方法。

譬如,我們可以利用這個支援來重寫我們的Detail action方法來,將其簡化,象下面這樣:

除了從請求的查詢字串/表單集合中映射參數值外,ASP.NET MVC架構還允許你使用MVC URL route映射基礎設施在核心URL本身內嵌參數值(譬如,不是使用/Products/Detail?id=3,而是使用 /Products/Detail/3 )。

當你建立一個新的MVC項目時,聲明的預設的路徑映射規則擁有這樣的格式,“/[controller]/[action]/[id]”。這意味著,如果URL中在控制器名稱和action名稱之後還有任何子路徑的話,在預設情形下,它將作為一個名為“id”的參數處理,會自動地作為一個方法參數傳給我們的控制器action方法。

這意味著我們現在可以使用我們的Detail 方法來處理從URL路徑(譬如/Products/Detail/3)中擷取ID參數:

我可以對List action使用類似的方法,這樣我們可以將分類名稱作為URL的一部分傳進來(譬如:/Products/List/Beverages)。為了使得代碼容易閱讀,我對routing規則做了一個小變動,這樣不是把參數名定為“id”,對這個action,它被稱作“category”。

下面是實現了完整URL routing和參數映射支援的ProductsController類的一個版本:

注意上面List action方法接受一個作為URL一部分的category參數,然後一個作為URL查詢字串一部分的可預設的網頁索引參數(我們將實現伺服器端分頁,將使用該參數值來表示我們應該顯示對應分類資料的哪一頁)。

我們的MVC 架構中的可預設的參數是通過Controller Action方法上nullable的型別參數來處理的。因為我們List action的分頁參數是個nullable的int,從文法上來說,即是int? ,如果這個參數存在於URL中,MVC架構會將其值傳給對應方法,如果不存在,會傳入null。參閱我以前的關於?? null coalescing operator文章以瞭解如何操作象這樣傳入的nullable型別參數的一個有用的技巧/訣竅。

建造資料模型對象

至此,我們有了一個 ProductsController類,內含三個action方法,準備好處理進來的web請求了。下一步將是建造一些類,來幫我們操作資料庫,從中擷取處理這些請求所需的適當的資料。

在MVC世界裡,“model(模型)”是負責保持狀態的應用組件。在web應用中,這個狀態一般都持久於資料庫之中(譬如,我們也許有一個Product 對象,用來代表我們SQL資料庫裡Products表中的產品資料)。

ASP.NET MVC架構允許你為擷取和管理你的模型,可以使用你想要的任何資料訪問模式或架構。如果你要使用ADO.NET DataSets/DataReaders (或者建於它們之上的抽象),你可以那麼做。如果你更喜歡使用象NHibernate, LLBLGen, WilsonORMapper, LINQ to SQL/LINQ to Entities這樣的對象關係映射器(ORM),你也絕對可以那麼做。

對我們的電子商務常式,我想用隨 .NET 3.5 和 VS 2008發布的內建LINQ to SQL ORM 。你可以從我的還在撰寫中的討論LINQ to SQL 的部落格系列中瞭解其中詳情,特別是一定要閱讀一下其中的第一部分,第二部分,第三部分,和第四部分的文章。

從右擊VS中的MVC web項目的“Models”子目錄開始,選擇“添加新項”,加一個 LINQ to SQL 模型。在LINQ to SQL ORM 設計器中,我將定義三個資料模型類,分別映射到SQL Server Northwind資料庫中的Categories, Products, 和Suppliers 表(閱讀我的LINQ to SQL 系列的第二部分學習該怎麼做):

定義完LINQ to SQL 資料模型類之後,然後我還將添加一個新NorthwindDataContext部分類到我們的Models目錄中:

在這個類中,我將定義幾個輔助方法封裝一些LINQ運算式,這些運算式是用來從資料庫中擷取獨特的Category對象,擷取指定分類的所有Product 對象,以及基於指定的ProductID擷取單獨的 Product對象:

這些輔助方法將方便我們在ProductsController類中乾淨利索地擷取所需的資料模型對象 (而不用在Controller類中編寫LINQ運算式):

至此,我們就有了為完成我們的ProductsController功能所需的所有的資料代碼和對象。

完成ProductsController類的實現

基於MVC的應用中的控制器類負責處理到來的請求,處理使用者輸入和互動,並且基於這些輸入和互動執行適當的應用邏輯(擷取和更新儲存在資料庫中的模型資料等等)。

控制器一般對請求產生特定的HTML響應。產生HTML響應的任務是為應用中的“視圖”組件所擁有,這些視圖是通過獨立於控制器的單獨的類或模板實現的。視圖的目的是完全注重於封裝表現層的邏輯,不應該包含任何應用邏輯或資料庫資料擷取的代碼的(所有的應用邏輯應當為 Controller來處理)。

在一個典型的MVC web流程中,控制器action方法負責處理進來的web請求,使用傳入的參數值執行適當的應用邏輯代碼,從資料庫中擷取或更新資料模型對象,然後選擇使用一個“視圖”來顯示返回給瀏覽器的介面響應。作為選擇適當的視圖來顯示的一部分,控制器會明確地以參數的形式向“視圖”傳入視圖所需的所有的資料和變數,以使後者顯示適當的響應:

你也許在想,象這樣分開Controller和View有什麼好處呢?為什麼不把它們放在同一個類裡呢?象這樣分割應用的主要動機在於協助你加強應用/資料邏輯與你的介面產生代碼間的分離。這可以在隔離你的介面顯示邏輯的情形下,極大地方便你單元測試你的應用/資料邏輯。它還有助於使得你的應用更好維護,因為它妨礙了你無意中把應用/資料邏輯加到你的視圖模板裡的可能。

在實現我們ProductsController類的三個控制器action方法時,我們將根據進來的URL參數值從資料庫中擷取適當的模型對象,然後選擇一個“視圖”組件來顯示適當的HTML響應。我們將使用Controller基類的一個RenderView() 方法來指定我們想要使用的視圖,以及明確地把我們要視圖在顯示響應時使用的特定資料傳入該方法。

下面是我們的ProductsController實現的最終結果:

注意,我們的action方法的程式碼數目很小(每個方法只有2行),部分原因是因為URL參數分析邏輯完全是由MVC架構為我們做的(給我們省了很多行代碼),還有部分原因是因為產品瀏覽情境從商務邏輯的角度來說相當簡單(涉及的action方法都是唯讀顯示情境)。

但總的來說,你經常會發現你有的都是些有時被稱為“瘦控制器”的東西,即控制器方法充滿了相當簡短的action方法(少於10行代碼)。這經常是好的跡象,表明你非常乾淨地封裝了你的資料邏輯,也非常好地分隔了你的控制器邏輯。

單元測試ProductsController

你也許會感到驚奇,我們要做的下一步居然是測試我們的應用邏輯和功能。你也許會問,這怎麼可能呢?我們還沒有實現我們的視圖呢,我們的應用目前並不顯示一個HTML tag。其實呢,使得MVC方法有魅力的部分原因就是我們可以完全獨立於視圖/Html產生邏輯來測試Controller和Model 邏輯。在下面你將看到,我們甚至可以在建立視圖前單元測試這些對象。

為單元測試我們在編寫的ProductsController類,我們將往測試專案裡加一個ProductsControllerTest類,這個測試專案是在我們使用Visual Studio建立我們的ASP.NET MVC應用時,預設添加到我們的解決方案裡的:

然後我們將定義一個簡單的單元測試,測試我們的ProductsController的 Detail action方法:

ASP.NET MVC 架構是特地設計來促成輕鬆的單元測試的。架構中的所有的核心API和契約都是介面,提供了大量的擴充點以促成輕鬆的對象注入和定製(包括使用象 Windsor, StructureMap, Spring.NET, 和ObjectBuilder這樣的IOC容器的能力)。開發人員將能夠使用內建的mock類,或者使用任何.NET 類型mock架構來類比他們自己的MVC相關對象的測試版本。

在上面的單元測試中,你可以看到一個例子,我們是如何在調用 Detail() action 方法之前,往我們的ProductsController裡注入了一個偽(dummy)“ViewFactory”實現的。這麼做的話,我們就覆蓋了預設的ViewFactory,否則的話,預設的ViewFactory會建立和顯示我們的視圖。我們可以使用這個測試ViewFactory實現來做隔離,只對我們ProductController的Detail action的行為進行測試(而不必調用實際的視圖來做測試)。注意我們是如何在Detail() action方法被調用之後,使用了三個 Assert 語句來核實該方法的正確的行為確實發生了(具體地說,該方法擷取了正確的Product對象,然後將它傳給了適當的視圖)。

因為我們可以mock和類比MVC架構中的任何對象(包括 IHttpRequest 和 IHttpResponse 對象),你不用再在web服務的環境裡運行單元測試,我們可以在常規的類庫裡建立我們的ProductsController對象,然後對它直接測試。這可以極大地加快單元測試的運行速度,以及簡化對它們的配置和運行。

如果我們使用 Visual Studio 2008 IDE,我們還可以輕易地跟蹤我們運行測試的結果(這個功能現在已經成為VS 2008 專業版的一部分):

我想你會發現ASP.NET MVC 架構極大地方便了測試的編寫,而且促成了非常好的TDD流程。

使用視圖顯示介面

我們完成了我們電子商務應用的產品瀏覽部分的應用+資料邏輯的實現和測試,現在我們需要實現相關的HTML介面。

我們將通過實現“視圖”來實現,這些視圖將使用我們ProductsController的action方法在調用RenderView() 方法時提供的跟視圖有關的資料對象,來顯示適當的介面:

在上面的代碼例子裡,RenderView方法的“Categories”參數表示我們要顯示的視圖名稱,第二個參數是我們要傳給視圖對象並要視圖對象據此顯示適當HTML介面的分類對象的列表。

ASP.NET MVC架構支援使用任何模板引擎(包括象NVelocity, Brail,以及你自己想要編寫的任何模板引擎)來協助產生介面。在預設情形下, ASP.NET MVC 架構使用ASP.NET中現有的ASP.NET 頁面 (.aspx), 主版頁面 (.master), 和使用者控制項 (.ascx) 。

我們將使用內建的ASP.NET 視圖引擎來實現我們的電子商務應用的介面。

定義Site.Master檔案

因為我們將要在網站上建造很多頁面,我們先來定義一個主版頁面,用以封裝整個網站公用的HTML布局/樣式。我們將在我們項目的\Views\Shared 目錄裡建立一個名為“Site.Master”的檔案:

我們可以引用一個外部的CSS樣式檔案來封裝整個網站的所有樣式,然後使用主版頁面來定義網站總的布局,以及指定我們要具體頁面填充相關內容的內容placeholder 地區。在做的時候,我們也可以使用VS 2008 中的新設計器的所有的酷功能,包括HTML分割視圖設計器,編著CSS和嵌套主版頁面支援等。

理解/Views目錄結構

在預設情形下,當你使用Visual Studio建立新的ASP.NET MVC 項目時,它會在“Views”根目錄下產生一個“Shared”子目錄。這是存放應用中為多個控制器所共用的主版頁面,使用者控制項和視圖的推薦使用的地點。

在建造為特定個別控制器所用的視圖時,預設的 ASP.NET MVC 約定是,把它們存放在\Views 根目錄的子目錄裡。在預設情形下,子目錄的名字應該對應於控制器的名字。譬如,因為我們正編寫的Controller類叫 “ProductsController”,在預設情形下,我們將在\Views\Products 子目錄裡存放跟它相關的特定視圖:

當我們在一個特定的Controller中調用 RenderView(string viewName)方法時,MVC架構會自動地首先在\Views\ControllerName 目錄裡尋找對應的.aspx 或 .ascx視圖模板,如果它找不到適當的視圖模板,然後它會在 \Views\Shared目錄尋找。

建立一個Categories視圖

我們可以在 Visual Studio 中 Products 目錄上使用“添加新項”菜單選項,然後選擇“MVC視圖網頁”項目範本,為我們的ProductsController 建立一個“Categories”視圖。這會產生一個新的.aspx 頁面,我們可以將它跟我們的 Site.Master主版頁面相關聯,來得到總的外觀(就象主版頁面一樣,你會得到即見即所得設計器的支援):

在使用MVC模式建造應用時,你要把你的視圖代碼儘可能地保持簡潔,確認視圖代碼純粹是用來顯示介面。應用和資料擷取邏輯應該只在 Controller類裡編寫。然後Controller類就可以在調用RenderView 方法時選擇把所需的資料對象傳遞給視圖。譬如,在下面,我們的ProductsController類的 Categories action方法中,我們把 一個Category對象的List集合傳給了Categories視圖:

MVC視圖頁預設是從System.Web.Mvc.ViewPage 基類繼承而來的,該基類提供了可為我們構建介面時所用的許多特定於MVC的輔助方法和屬性。ViewPage的其中一個屬性名稱叫“ViewData”,通過它,你可以訪問Controller作為參數傳給 RenderView()方法的特定於視圖的資料對象。

從你的視圖裡,你可以後期綁定或以強型別的方式訪問“ViewData”。如果你的視圖是從ViewPage繼承而來,那麼ViewData屬性是個後期綁定的字典。如果你的視圖是從基於泛型的ViewPage<T>繼承而來,其中T表示Controller傳給視圖的ViewData 的資料對象的類型,那麼ViewData屬性就是強型別的,匹配你的Controller傳入的資料的類型。

譬如,如下所示的我的Categories視圖的後台類是從ViewPage<T>繼承而來,我指明T為Category對象的一個List

這意味著在我的視圖代碼裡操作ProductsController.Categories() 提供的List<Category> ViewData時,我將得到完整的型別安全, intellisense和編譯時間檢查:

顯示Categories視圖:

如果你還記得本文章最前面的的話,我們要在我們的 Categories 視圖裡顯示產品分類列表:

我可以在我的Categories視圖實現裡用2種方式編寫這個HTML介面產生代碼:1) 在.aspx 檔案裡使用行內代碼, 或者 2) 在.aspx 檔案中使用伺服器控制項,然後在後台代碼裡使用資料繫結。

顯示方法1:使用行內代碼

目前的ASP.NET網頁, 使用者控制項和主版頁面支援使用 <% %> 和 <%= %>的句法來在html 標識內嵌入顯示代碼。我們可以在Categories 視圖裡使用這個技巧,輕鬆地編寫一個foreach迴圈,來產生HTML分類列表:

VS 2008在源碼編輯器內為VB和C#提供完整的代碼intellisense。這意味著,在對傳入視圖的Category模型對象操作時,我們將得到intellisense:

VS 2008還為行內代碼提供了完整的調試器支援(允許我們在調試器對視圖中的代碼設定斷點以及動態檢查任何東西):

顯示方法2:使用伺服器端控制項

ASP.NET網頁,使用者控制項和主版頁面還提供對使用聲明式伺服器端控制項封裝HTML介面產生的支援。不是象上面那樣使用行內代碼,我們可以使用 .NET 3.5中新的<asp:listview> 控制項來產生列表介面:

注意上面 ListView 控制項封裝了顯示值列表的情形,還負責處理列表中沒有任何東西的情形(<EmptyDataTemplate>省略了需要在標識中編寫 if/else 語句的麻煩)。然後我們可以象下面這樣,在後台代碼裡,將我們的分類對象綁定到listview控制項上:

重要注意事項:在MVC世界裡,我們只想要把顯示代碼放在我們視圖的後台代碼裡,不包括任何應用或資料邏輯。注意上面我們只有把強型別的 Category對象的ViewData集合賦值給ListView控制項的邏輯。我們的ProductsController控制器類才是實際從資料庫擷取Category對象列表的責任者,不是視圖。

我們視圖模板的ListView伺服器端控制項版本然後就會產生跟上面行內代碼版本完全一樣的HTML。因為我們在頁面裡沒有 <form runat="server">控制項,ViewState,ID值以及其他的標識都不會產生,只有純粹的CSS友好的HTML:

 

Html.ActionLink方法

你也許注意到的一件事情是,在上面視圖代碼片斷中行內代碼以及伺服器端控制項兩個版本中對一個Html.ActionLink 方法的調用:

Html對象是 ViewPage 基類的一個輔助屬性,ActionLink方法是它的一個輔助方法,它方便你動態地產生連回到控制器的action 方法的HTML超連結。如果你看一下上面產生的HTML輸出圖,你可以看到一些由該方法產生的一些HTML輸出例子:

<a href="http://weblogs.asp.net/Products/List/Beverages">Beverages</a>

我使用的Html.ActionLink方法的簽名是這樣的:

string ActionLink(string text, object values);

第一個參數表示要顯示的超連結的內容(譬如<a>這裡是文字</a>),第二個參數是個匿名對象 ,它代表用以產生實際URL的一串值,你可以認為它是產生字典的一個比較乾淨的方式。我會在將來討論URL routing引擎的部落格文章裡仔細討論這個參數的運用情形。但簡而言之,你可以使用URL routing系統既處理進來的URL,也可以用它來產生你可以在返回的HTML輸出的URL。如果我們的routing規則是象這樣的:

/<controller>/<action>/<category>

那麼在ProductController的Category視圖裡編寫這樣的代碼時:

<%= Html.ActionLink("Click Me to See Beverages", new { action="List", category="Beverages" } %>

ActionLink方法就會使用你應用的URL映射規則,換進你的參數,產生這樣的輸出:

<a href="http://weblogs.asp.net/Products/List/Beverages">Click Me to See Beverages</a>

這方便了在你應用中產生URL和到你的控制器的AJAX回調。它也意味著你可以在一個地方更新你的URL routing規則,你整個應用中的代碼會在對進來的URL的處理和外出的URL的產生過程中自動採用新的變化。

重要注意事項:為加強可測試性,目前的MVC架構並不支援你視圖中針對伺服器端控制項的postback事件,取而代之的是,ASP.NET MVC應用產生超連結和對控制器action的AJAX回調,然後只使用視圖(以及其中的任何伺服器端控制項)顯示輸出。這有助於確保你的視圖邏輯保持在最小限度,只注重於顯示,以及你可以單元測試你的Controller類,獨立於你的視圖,核實所有的應用和資料邏輯行為。我在將來的文章裡會對此做更深入的討論。

結語

這第一個貼子非常長,但希望它對新的ASP.NET MVC架構中所有不同的組件是如何組合在一起的,如何使用它打造常見的現實世界情境的應用提供了一個相當廣泛的綜覽。 ASP.NET MVC的第一個公開預覽版將在幾個星期內發布,你將能夠使用它來做我上面描述的一切。

雖然很多MVC固有的概念(特別是關注分離的觀念)對該貼子的很多讀者來說是比較新的,但希望本貼子展示了我們正在開發的ASP.NET MVC實現是如何很乾淨地嵌合到現有的ASP.NET, .NET, 和 Visual Studio架構中的。你可以使用.ASPX, .ASCX 和 .MASTER檔案以及ASP.NET AJAX建立你的ASP.NET MVC 視圖。今天ASP.NET中的非介面功能,譬如表單認證, Windows認證, 成員,角色, Url授權, 緩衝, Session 狀態, 使用者資訊,健康監測, 配置,編譯,本地化以及 HttpModules/HttpHandlers 都是完全支援MVC模型的。

如果你不喜歡MVC模型,或者發現它對你的開發風格來說並不自然的話,你完全不必強用它的。它完全只是提供選項,並不替代現有的 WebForms Page Controller 模型。WebForms和MVC這2個模型在以後都會得到完全支援和改進。如果你想的話,你甚至可以建造一個應用,部分使用WebForms編寫,部分使用MVC編寫。

如果你喜歡上面貼子裡的東西的話(或者感興趣想進一步瞭解的話),留意一下我這段時間的部落格。我將進一步討論MVC概念,使用它們來進一步建造我們的電子商務應用,展示更多的MVC特性。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.