前幾周我發表了一系列文章介紹我們正在研究的ASP.NET MVC架構。ASP.NET MVC架構為你提供了一種新的開發Web應用程式的途徑,這種途徑可以讓應用程式變得更加層次清晰,而且更加有利於對代碼進行單元測試和支援TDD(測試驅動開發)開發。
這一些列的第一篇文章建立了一個簡單的電子商務產品列表/瀏覽網站。他涉及到了MVC背後的高層次概念並示範了一個ASP.NET MVC項目從設計到實現的過程和對產品列表功能的測試。該系列的第二篇文章深入介紹了ASP.NET MVC架構的URL映射機制並針對其工作原理和更複雜URL映射的處理進行了深入討論。第三篇文章討論了控制類和視圖的互動,並專門介紹了從控制類向視圖中傳遞資料用於產生用戶端轉譯的方法。
今天這篇文章將要討論如何使用ASP.NET MVC架構處理表單輸入提交操作.,同時討論一些可以用於簡化資料編輯的HTML輔助擴充方法。點擊這裡下載完整的應用程式代碼以便於你理解這些概念。
表單輸入和提交操作
為了說明如何使用ASP.NET MVC 架構對錶單編輯和提交進行基本操作,我們將要建立一個簡單的產品列表/產品建立和產品編輯應用。他將為使用者提供三種核心的功能:
根據目錄列出產品
使用者可以通過/Products/Category/[CategoryID]地址訪問某一目錄下的產品列表:
添加新產品
使用者點擊“Add New Produt”連結可以向商店中添加新產品,該連結將使用者連結到/Products/New地址,允許使用者輸入添加產品的詳細資料。
點擊儲存按鈕,產品將被添加到資料庫中,頁面返回到產品列表頁。
編輯產品
在產品列表頁使用者可以點擊每項產品旁邊的“Edit”連結到/Products/Edit/[ProductID]地址,允許使用者修改對應產品的詳細資料,點擊儲存按鈕時將新資訊儲存到資料庫中。
資料模型
我們使用SQL Server的Northwind樣本資料庫儲存我們的資料。我們將對產品(Product)、目錄和(Category)供應(Supplier)商對象及其資料庫表中對應的行應用.NET3.0中內建的LINQ to SQL 實體關聯映射機制。
右單擊ASP.NET MVC項目中的/Model子目錄,選擇“添加新項目”->“LINQ to SQL 類”,開啟LINQ to SQL ORM 設計器並對資料對象建模:
然後我們要在項目中建立NorthwindDataContext分布類並添加一些輔助方法。我們定義這些輔助方法出於兩點考慮:1)避免直接向Controller類中嵌入LINQ查詢語句2)為以後對Controller控制類使用依賴項(Dependency injection)注入做準備。
我們要添加的NorthwindDataContext輔助方法如下:
點擊這裡查看LINQ to SQL 系列文章瞭解更多關於LINQ to SQL的知識。
建立ProductsController類
我們將使用ProductsController類實現前面提到的3種核心功能(通過右單擊Controllers子檔案夾並選擇“添加新項目”->“MVC控制類”建立):
ProductsController類將要通過實現Category, New和Edit方法處理類似/Products/Category/3, /Products/New和/Products/Edit/5的URLqingqiu .
請閱讀本系列的Part 1和Part 2瞭解更多關於URL到控制方法映射的內容。
控制類方法將通過三個視圖(Views)頁面實現產生輸出內容。/Views/Products子目錄下的”List.aspx””New.aspx”和”edit.aspx”頁面,他們共同使用\Views\Shared目錄下的Site.Master母板頁。
依據目錄顯示產品列表的顯示
我們首先實現產品列表的URL請求/Products/Category/[CategoryId]:
我們使用ProductsController中的”Category”方法實現該功能,並使用LINQ to SQL DataContext類中的GetCategoryById輔助方法擷取在URL(例如/Products/Category/3)中指定的某一目錄對象,然後將該目錄對象傳入”List”視圖,並顯示輸出:
為了實現List視圖,首先將該頁面的後台代碼檔案修改為繼承自ViewPage<Category>基類,將頁面的接收到的來自Controller控制類的ViewData屬性類型定義為Category(Part 3中有詳細討論):
List.aspx的實現如下:
上面的視圖在頁面頂部顯示了目錄名稱,並顯示該目錄的產品列表。
列表中每一產品項的旁邊為“編輯”連結。我們將使用Part 2中提到的Html.ActionLink()輔助方法來產生HTML連結(例如:<a href=”/Products/Edit/4”>Edit</a>),點擊該連結時進行編輯操作。同時我們要使用該方法在頁面底部產生<a href=”/Products/New”>Add New Product</a>連結,點擊該連結進行“New”操作。
當我們開啟/Products/Category/1地址並在瀏覽器中查看原始碼時,你將會發現我們的ASP.NET MVC應用程式遷入了整潔的HTML和URL標記:
添加新產品功能的實現(1- 背景)
我們接下來要實現“添加新產品”功能。我們最終希望使用者訪問/Products/New地址時可以看到下面的介面:
在ASP.NET MVC架構中表單輸入和編輯通常是由Controller類中的兩個方法實現的。第一個方法用於產生並發送包含表單的HTML代碼,另一個用於處理瀏覽器發回的提交資訊。
例如,對於上面的“添加產品”表單,我們可以通過ProductsController中的兩個方法來實現:“New”和“Create”。/Products/New請求將用於顯示包含用於輸入產品資訊的HTML文字框和下拉式功能表控制項的空表單。該頁面的HTML <form>元素的action屬性將設定為/Products/Create,這意味著當使用者點擊提交表單按鈕時,表單的輸入資訊將被發往“Create”方法處理並更新資料庫。
添加新產品的實現(2-第一種方式)
下面是我們可以用於ProductsController類的實現:
注意上面的代碼,在產品建立過程中我們要使用到兩個方法“New”和“Create”。“New”方法向使用者呈現一個空白表單,“Create”方法處理表單中提交的資料,在資料庫中建立一個新的產品,並將瀏覽器定位到產品列表頁。
“News.aspx”定義了發往用戶端的HTML表單並被New方法調用。其實現(均使用TextBox實現)如下:
注意我們是如何使用標準的HTML <form>元素的(不是form runat=server)。表單的action屬性將資料提交交給ProductController類的Create方法處理。當底部的<input type=”submit”>元素被點擊時提交資料,此時ASP.Net MVC 架構將自動將ProductName, CategoryID, SupplierID和UnitPrice的值作為Create方法的參數傳入。
運行已經具有基本產品項功能的網站:
添加新產品的實現(3-對下拉式清單使用HTML輔助)
我們前面已經完成了產品項頁面,但介面還不夠友好。因為使用者在添加產品時必須知道原始的CategoryID和SupplierID。我們希望顯示HTML下拉式清單來顯示有好的目錄名稱來解決該問題。
我們的第一步是修改ProductsController使其向視圖中傳遞兩個集合資料,一個包含可以用的目錄列表,另一個可以是可用的供應商列表。我們建立一個強型別的ProductsNewViewData類封裝這些資料,並傳遞給視圖(Part 3詳細介紹了該部分內容):
我們要更新“New”方法處理這些集合資料並作為ViewData傳遞給“New”視圖:
在我們的視圖中我們可以使用這些集合資料產生HTML的下拉式清單。
ASP.NET MVC HTML輔助方法
我們可以使用在HTML中使用<%%>嵌入包含if/else的for迴圈語句來產生下拉式清單,通過該種方式我們可以對HTML具有完全的控制權,但這樣會使得HTML代碼變得混亂。
你也可以選擇使用ViewPage基類中的“Html”輔助屬性。該對象實現了一些列HTML UI輔助方法自動完成Html UI產生。例如前面提到的使用Html.ActionLink輔助方法產生<a href=’’>元素:
HtmlHelper對象(包括後面將要提到的AjaxHelper對象)被設計成便於使用“擴充方法Extension Methods”(VS2008中VB和C#的新語言特性)使得任何人都可以在該對象中建立自訂的輔助方法並使用。
在以後的ASP.NET MVC架構中我們將提供更多內建的HTML和AJAX輔助方法。在第一個預覽版本中只是在System.Web.Extensions(ASP.Net MVC架構當前實現的程式集)嵌入了“ActionLink”方法。我們同時提供了一個獨立的MVCToolkit下載,你可以使用它像項目中更多的輔助方法。
使用MVCToolkit HTML輔助方法,只需要將MVCToolkit.dll程式集添加到你的項目引用中:
重新編譯項目,下次使用<%=HTML.%>時,你將會看到更多的UI輔助方法:
我們可以使用Html.Select()方法來構建HTML <select>下拉式清單,每一個方法包含多個重載版本,並都具有智能感知支援:
我們可以在“New”視圖中使用Html.Select選項顯示下拉式清單,並用CategoryID/SupplierID作為值屬性,用CategoryName/SupplierName作為顯示文字屬性,代碼如下:
在運行時將產生對應的<select> HTML標記:
這使使用者可以更簡單的選擇產品目錄和供應商資訊:
注意:因為我們仍然提交CategoryID和SupplierID值,因此我們不需要針對新的下拉式清單介面更新ProductsController的Create方法。
添加新產品的實現(4-使用UpdateForm方法結束建立過程)
我們的ProductsController類的Create方法用於處理添加產品表單提交的資料,目前該方法通過將表單資料作為參數傳入方法:
雖然這種方式要在方法的簽名中指定大量的參數,但這種方式仍然是可以正常工作的,上面的代碼將所有傳入的表單值傳遞給Products對象,代碼仍然有些複雜。
如果你引用了MVCToolkit程式集,你可以選擇使用System.Web.Mvc.BindingHelpers命名空間中實現的一個Extension Method來簡化代碼。該方法是”UpdateForm”並可以引用於所有.NET對象。它包含了一個字典值作為參數,並將自動給對象中具有與鍵名同名的屬性進行複製。
例如,我們可以使用UpdateForm方法重寫Create方法:
注意:如果你希望處於安全原因更加嚴謹並只允許某些屬性被賦值,你可以選擇向UpdateForm方法中傳入一個包含需要更新的屬性名稱的字串數組:
編輯產品功能的實現(1-背景)
現在來實現網站的產品編輯功能。我們希望終端使用者看到訪問/Products/Edit/[ProductID]地址是看到下面的介面:
與上面添加產品的表單相似,我們使這個表單與ProductsController中的“Edit”和“Update”方法互動:
“Edit”顯示產品表單,“Update”用於處理提交資料。
編輯產品功能的實現(2-Edit方法)
我們通過實現ProductsController中的Edit方法來實現應用程式的編輯產品功能。當我們完成建立產品功能並編譯後,Edit()方法將要求URL 的一部分作為一個id參數(例如:/Products/Edit/5):
我們希望Edit方法可以從資料庫中擷取指定的產品對象和可用的供應商和產品集合(用於在編輯檢視中顯示下拉式清單),我們可以定義一個強型別的ProductsEditViewData視圖資料對象代表。
我們可以通過實現Edit方法來處理ViewData對象並通過“Edit”視圖進行呈現:
編輯產品功能的實現(2-編輯檢視)
我們可以通過下面的方式實現Edit.aspx視圖頁:
注意上面的例子中我們是如何使用Html.TextBox和Html.Select輔助方法的,這兩個輔助方法均來自MVCToolkit.dll 程式集。
注意Html.Select輔助方法提供了一個重載方法允許你指定下拉式功能表中的選中值,在下面的程式碼片段中,產品目錄下拉式清單中的選中項目自動化佈建為當前產品的目錄的選中值:
最後,注意我們使用Url.Action()輔助方法設定<form>元素的action屬性:
Url.Action和Html.Action方法使用了ASP.NET MVC架構的映射引擎產生URL(Part 2中詳細介紹了該部分內容).通過這種凡是,只要我們修改了網站的映射規則,我們不需要修改控制類或視圖中的任何代碼。例如,我們可以使用一個更加REST的路徑,例如使用/Products/1/Edit取代/Products/Edit/1,控制類和視圖不需要做任何修改仍可以正常工作。
編輯產品功能的實現(3-Update方法)
我們的最後一步是實現ProductsController中的Update方法:
在前面的Create方法中我們使用了UpdateForm擴充方法來自動從請求中擷取產品對象,而在這裡我們需要首先從資料庫中擷取原始的對象資料,然後將使用者所做的修改應用到對象,並將修改儲存到資料庫中。
修改成功後,頁面返回到產品列表也並自動將對產品所做的修改應用的對應得列表中。
總結
希望這篇文章對ASP.NET MVC架構對錶單輸入和調的處理進行了清晰的描述,同時提供了採用該方式針對普通資料項目進行編輯和處理的例子。
點擊這裡下載包含該應用程式的代碼檔案。
後面的文章將介紹如何對錶單輸入和編輯應用進行資料驗證和錯誤捕獲。我將會介紹用於快速開發內建資料和安全支援,同時我們將討論在MVC架構中如何使用ASP.NETAJAX來實現AJAX,並深入討論單元測試的進行和對Controller依賴性注入(Dependencies injection)的操作。
希望對你有所協助,
Scott