ASP.NET MVC 第五個預覽版和表單提交場景
上個星期四,ASP.NET MVC開發團隊釋出了ASP.NET MVC框架的“第五個預覽版”。你可以在這裡下載這個新版本。這“第五個預覽版” 可在.NET 3.5和最新發布的.NET 3.5 SP1下工作,也可在Visual Studio 2008以及免費的Visual Web Developer 2008 Express SP1版本(現在支援類庫專案和web應用專案了)下使用。
第五個預覽版包含了建立在“第四個預覽版”的新功能之上的一堆新功能和改進。你可以在這裡閱讀“第五個預覽版”的釋出說明,其中總結了所做變動和新添特性。在這個部落格貼子中,我將討論這個版本中一個最大的關注點:表單提交場景。你可以在這裡下載我將在下面建造的一個應用的完整版本。
Web MVC模式中的基本表單提交
讓我們看一個簡單的表單提交場景,往產品資料庫中加一個新產品:
上面的頁面是在使用者訪問我們應用的“/Products/Create”URL時返回的,該網頁的的HTML表單標識如下:
上面的標識是標準的HTML,在
單元測試和UpdateModel
在這個星期的第五個預覽版中,UpdateModel方法總是從Request物件的Form提交集合中取得數值的,這意味著,要測試上面的表單提交action方法,你需要在你的單元測試裡模擬Request物件。
在下一個MVC版本中,我們還將加一個過載的UpdateModel方法,它將允許你傳入一個你自己的數值集合為它所用。例如,我們將能夠使用第五個預覽版中的新的FormCollection型別(有一個ModelBuilder物件會自動地使用所有的表單提交值來填充它),將它作為引數傳給UpdateModel方法,象這樣:
使用象上面這樣的方法將允許我們不用使用任何模擬,就可以單元測試我們的表單提交場景。下面是我們可以編寫的一個單元測試的例程,用來測試一個POST場景用新的數值成功地更新,然後重新定向到我們action方法的GET版本。 注意,為單元測試我們的controller的所有功能,我們不需要模擬任何東西(也不依賴任何特別的輔助方法):
處理錯誤場景 - 重新顯示帶錯誤訊息的表單
在處理表單提交場景時,一個需要注意的重要事情是處理出錯條件。這些情形包括,使用者提交了錯誤的輸入(例如,對型別是Decimal的單價,輸入了字串,而不是數字),以及輸入格式是合法的,但應用後面的業務規則不允許某些東西得到建立/更新/儲存(例如,對停賣了的產品的新的訂購)。
如果使用者在填表時犯了錯,表單應該重新顯示,並輸出清楚明確的錯誤資訊,引導使用者修正輸入。表單還應該保留使用者當初輸入的資料,這樣,他們就不用手工重填了。這個過程應該重複多次,直到表單成功完成為止。
ASP.NET MVC中的基本的表單錯誤處理和輸入驗證
在上面的產品編輯例程中,我們在Controller或View中都沒怎麼編寫錯誤處理程式碼。我們的Edit提交action方法只簡單地用了一個try/catch錯誤處理塊將UpdateModel()輸入對映呼叫以及資料庫儲存SubmitChanges()呼叫圍了起來。如果錯誤發生的話,controller將一個輸出訊息儲存到TempData集合中,然後返回/重新顯示我們的編輯檢視:
在ASP.NET MVC以前的版本中,上面的程式碼提供不了很好的使用者體驗(因為有錯的話,它不會高亮顯示問題所在,也不會保留使用者輸入)。
但在第五個預覽版中,你會發現,只用上面的程式碼,出錯時,你現在能得到一個不錯的使用者體驗。特別地,你會發現,當我們的編輯檢視因為輸入錯誤重新顯示時,它會高亮顯示所有有問題的輸入控制元件,同時保留它們的輸入值,讓我們來修正:
你也許會問,單價文字框是如何用紅色高亮顯示自己,知道輸出原先輸入的使用者值的呢?
第五個預覽版引進了一個新的“ModelState”集合,該集合是在顯示時,作為ViewData的一部分,從Controller傳遞給View的。 ModelState集合給Controllers提供了一個方式,來表示傳給View的模型物件或模型屬性中有錯存在,允許指定一個描述問題所在的對人類友好的錯誤訊息,以及由使用者輸入的原始資料。
開發人員可以在Controller action方法中,明確地編寫程式碼往ModelState集合中新增個項。 ASP.NET MVC 的模型繫結器和UpdateModel()輔助方法也會在遇上輸入錯誤時自動地預設填充這個集合。因為在上面的Edit action方法中,我們使用了UpdateModel()輔助方法,在它試圖將單價文字框的“gfgff23.02”輸入對映到Product.UnitPrice(型別是Decimal)屬性時失敗了的時候,它會自動地往ModelState集合中加一項。
View中的Html輔助方法在預設情形下,在顯示輸出時,現在會檢視ModelState集合。如果它們正顯示的一項有錯存在的話,它們現在會將原先輸入的使用者資料顯示出來,同時會將一個CSS錯誤類顯示到HTML輸入控制元件元素上去。例如,在上面的“Edit”檢視中,我們使用了 Html.TextBox() 輔助方法來顯示我們Product物件的UnitPrice:
在上面的出錯場景下,檢視被顯示時,Html.TextBox()會檢視ViewData.ModelState集合,看我們的Product物件的“UnitPrice”屬性是否有問題,當它看到有問題時,它會將原先輸入的使用者資料"gfgff23.02"輸出,同時將一個css類加到它輸出的上去:
你可以將出錯css類的外觀定製成你想要的任何外觀,在新的ASP.NET MVC專案中建立的樣式表中輸入控制元件元素預設的出錯CSS規則如下所示:
新增額外的驗證訊息
內建的HTML表單輔助方法對有問題的輸入域提供了基本的視覺識別外觀。現在讓我們來往頁面上再加一些更具描述性的出錯資訊,具體做法是,我們可以使用第五個預覽版中這個新的Html.ValidationMessage()輔助方法,這個方法會輸出與一個給定Model或Model屬性相關聯的ModelState集合中的錯誤資訊。
例如,我們可以更新我們的檢視,在文字框的右方使用Html.ValidationMessage()輔助方法,象這樣
當頁面因錯而顯示時,錯誤訊息就會顯示在有問題的控制元件域之後:
Html.ValidationMessage() 方法還有一個過載的版本,接受第二個引數,允許檢視指定要顯示的替換文字:
常見的一個用例是,在輸入控制元件域後面輸出 * 字元,然後將新的Html.ValidationSummary()輔助方法(也是第五個預覽版中新加的)加到頁面的頂部,來列出所有的錯誤訊息:
Html.ValidationSummary()輔助方法然後就會用
注意,我們完全不用改動ProductsController類就取得了如此效果。
支援業務規則的驗證
象上面那樣支援輸入驗證場景是很有用的,但對大多數應用來說是不夠的。在大多數場景下,你還想要能夠執行業務規則,讓你應用的使用者介面能與它們乾淨地結合起來。
ASP.NET MVC支援任何的資料層抽象(無論是基於ORM與否),允許你對你的領域模型,以及相關聯的規則/限制進行任意的結構化。象模型繫結器, UpdateModel輔助方法,以及所有的錯誤顯示和驗證訊息支援這樣的功能,都是特意設計的,這樣你可以在你的MVC應用中使用你想要的任何首選資料訪問故事(包括LINQ to SQL, LINQ to Entities, NHibernate, SubSonic, CSLA.NET, LLBLGen Pro, WilsonORMapper, DataSets, ActiveRecord等等)。
往LINQ to SQL實體中新增業務規則
在上面的例子中,我一直在使用LINQ to SQL 來定義我的Product實體和進行資料訪問操作。迄今為止,在我的Product實體上使用的唯一領域規則/驗證是那些由LINQ to SQL從SQL Server後設資料(可空性,資料型別和長度等等)中推斷出來的那些規則,這會捉住象上面那樣的場景(我們試圖給一個Decimal賦一個有問題的輸入)。但是,它們無法構型那些使用SQL後設資料難以宣告的業務問題。例如,在一個產品停售之後,不能允許它的reorder(重訂購)水平大於0,或者不允許一個產品以小於供應商的價格出售,等等。對這樣的場景,我們需要在我們的模型中新增程式碼來表達和結合這些業務規則。
新增這些業務規則邏輯的錯誤地方是應用的UI層,在那裡加這些規則不好,有很多理由。特別值得一提的是,幾乎肯定會導致程式碼的重複,因為你最終會將這些規則從一個UI拷貝到另一個UI,從一個表單到另一個表單。除了費時外,這麼做,在你改變業務規則邏輯時,如果你忘了在所有的地方做更新的話,有很大的機率會導致缺陷。
一個融合這些業務規則的好得多的地方是你的模型或領域層,那麼做的話,不管是什麼型別的使用者介面或表單或服務,這些規則都可以被使用和執行。對規則的變動只要做一次,不用重複任何邏輯就可在任何地方使用。
我們有幾個模式和方法可用,來將豐富的業務規則整合到上面我們一直在用的Product模型物件中去:我們可以在物件中定義這些規則,也可在物件外面定義這些規則。我們可以使用宣告式規則,一個可重用的規則引擎框架,或者命令式程式碼(imperative code)。要點是,ASP.NET MVC允許我們使用任何一種方法或者所有這些方法(沒有一堆功能要求你總是採用一種方式做事,你擁有對它們進行變通的靈活性,MVC功能的擴充套件性之強大,幾乎可以與任何東西相結合)。
在本貼子中,我將使用一個比較簡單的規則的方法。首先,我將象下面這樣定義一個“RuleViolation”類,我們可以用它來捕捉住我們模型中正被違反的業務規則的資訊。這個類會呈現一個ErrorMessage字串屬性,內含錯誤的細節,以及呈現與之相關聯的造成規則違反的關鍵屬性名稱和屬性值:
(注:為簡單起見,我將只儲存一個屬性, 在更復雜的應用中,這也許會是一個列表,這樣就可以指定多個屬性。)
然後我將定義一個IRuleEntity介面,內含單個方法, GetRuleViolations(),將返回實體中所有業務規則違反的列表:
然後我可以讓我的Product類實現這個介面,為保持這個例子簡單起見,我將把規則定義和估算邏輯內嵌在方法之中。有更好的模式你可以用來促成可重用的規則,以及處理更復雜的規則。如果這個例程變大的話,我需要重構這個方法,這樣,規則以及它們的估算將被定義在其它地方,但目前為保持簡明,我們將象下面這樣估算三個業務規則:
我們的應用現在可以查詢Product(或任何其他IRuleEntity)例項來檢查它目前的驗證狀態,以及取回RuleViolation物件,這些物件可用來幫助顯示一個可以引導應用的使用者修正這些違反的使用者介面。它還允許我們獨立於應用的使用者介面來輕鬆地單元測試我們的業務規則。
在這個特定的例子裡,我將選擇確保,我們的Product物件在不合法的狀態下是不能儲存到資料庫中去的(意味著在Product物件可儲存到資料庫之前,所有的RuleViolations都必須被修正)。在LINQ to SQL中,我們可以這麼做,在Product部分類中,加一個OnValidate部分方法。這個方法會在資料庫持久化時,被LINQ to SQL自動呼叫。在下面我將呼叫我們在上面新增的GetRuleViolations()方法,如果有未解決的錯誤,我將丟擲一個異常。這會中止事務,防止資料庫被更新:
那樣,除了有個友好的輔助方法允許我們從一個Product中取出RuleViolations外,我們還確保在資料庫被更新之前那些RuleViolations必須被修正。
將上述規則整合進ASP.NET MVC使用者介面中
一旦象上面那樣實現了業務規則,呈示RuleViolations後,將其整合進我們的ASP.NET MVC例程則是比較容易的事情。
因為我們往Product類中加了OnValidate部分方法,呼叫northwind.SubmitChanges()會丟擲一個異常,如果我們試圖儲存的Product物件中有任何業餘規則驗證問題的話。這個異常會終止任何資料庫事務,在下面的catch塊中被捕捉住:
我們要往我們的錯誤catch塊中加的的一行額外程式碼是呼叫定義在下面的UpdateModelStateWithViolations()輔助方法的邏輯。這個方法從一個實體中取出所有的規則違反的列表,然後將適當的模型錯誤(包括對實體物件上導致錯誤的屬性的引用)更新ModelState集合:
完成之後,我們可以重新執行我們的應用。現在,除了看到與輸入格式相關的錯誤資訊外,ASP.NET MVC的驗證輔助方法還將顯示我們的業務規則的違反情形。
例如,我們可以將單價設成小於$1,將Reorder水平設成-1(從輸入格式的角度來看,這2個值都是合法的,但兩者都違反了業務規則)。當我們這麼做,點選儲存按鈕時,我們將看到Html.ValidationSummary()列表中的錯誤資訊,以及相關的文字框被特別標出了:
我們的業務規則可以跨越多個Product屬性,例如,你也許注意到了,我在上面加了一條規則說,如果產品被中止的話,reorder水平不能大於0:
在這整個業務規則過程中,對我們的“Edit”檢視模板要做的唯一變動是往檔案中再加2個Product屬性(Reorder和Discontinued):
現在我們可以往我們的Product實體中新增任何數目的額外業務驗證規則,而且為使得介面支援它們,我們不需要更新Edit檢視,也不要更新ProductsController。
我們還可以獨立於我們的Controller和View,對我們的模型和業務規則進行單獨的單元測試。我們也可以獨立於我們的Controller, Views 和 Models對URL路徑選擇規則進行單獨的單元測試。我們可以獨立於我們的Views單獨單元測試我們的Controller。本部落格貼子展示的所有場景都不要求使用任何模擬(mocking)或替補(stubbing)就支援單元測試,最終的結果是極其容易測試的應用,而且支援很好的TDD工作流程。
結語
本貼子對錶單提交場景在ASP.NET MVC第五個預覽版中的工作原理做了一個簡單的介紹,希望在閱讀之後,你對如何使用MVC模型處理表單和輸入場景有了更好的認識,你可以在這裡下載我在上面建造的應用的完整C#版本。本星期稍後,我將釋出相應的VB版本(不幸的是,在我鍵入該文字的時候,已經是臨晨4:30了,我需要在幾個短短的小時後跳上一架飛機,但現在還沒有開始收拾行裝呢)。
重要事項: 如果你不喜歡MVC模型,或者發現它與你的開發風格相違的話,你不一定要用它。這產品完全是個可選項,它並不替代現有的WebForms模型。WebForms和MVC模型以後都會被同時支援和增強(下一個ASP.NET WebForms版本將增加更豐富的URL路由特性,更好的HTML標識/客戶端ID/CSS支援等等)。所以,如果在閱讀了上面的貼子之後,你認為“呃,我感覺這不是很自然”,那麼不用擔心,也不用覺得你應該或者需要使用它,你不用那麼想。
在下一個MVC貼子裡,我將討論如何將AJAX整合進你的ASP.NET MVC應用。
希望本文對你有所幫助,
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/12639172/viewspace-621004/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Asp.Net Mvc5表單提交之List集合ASP.NETMVC
- Spring MVC表單防重複提交SpringMVC
- ASP.NET MVC/Core表單提交後臺模型二級屬性驗證問題ASP.NETMVC模型
- 提交表單
- .NET 6 預覽版 7 釋出——最後一個預覽版
- 如何優雅的提交一個表單
- jquery ajax方式直接提交整個表單jQuery
- PbootCMS使用者提交表單和調取表單記錄boot
- .NET 7 預覽版2 中的 ASP.NET Core 更新ASP.NET
- form表單提交方式ORM
- Laravel 的 表單驗證,多場景Laravel
- 【譯】.NET 7 預覽版 1 中的 ASP.NET Core 更新ASP.NET
- 更新丨.NET 7 預覽版2 中的 ASP.NET CoreASP.NET
- 一個表單同時提交多條記錄
- 重要·Flutter 首個預覽版 釋出Flutter
- 重要·Flutter首個預覽版釋出Flutter
- Gin(四):表單提交校驗和模型繫結模型
- win10正式版和預覽版的區別_win10正式版和預覽版圖文詳解Win10
- js表單檔案提交JS
- Ajax 提交表單資料
- 建立一個ASP.NET MVC 5專案ASP.NETMVC
- ASP.NET MVC三個重要的描述物件ASP.NETMVC物件
- django通過form和ajax提交表單資料和圖片DjangoORM
- jFinal避免表單重複提交
- PHP 防止表單重複提交PHP
- form表單提交注意事項ORM
- java 表單避免重複提交?Java
- ASP.NET + MVC5 入門完整教程三 (上) --- 第一個 MVC 專案_lingshuangcanxue-CSDN 部落格_asp.net mvcASP.NETMVCGC
- ASP.NET MVC路由ASP.NETMVC路由
- ASP.NET MVC – 樣式和佈局簡介ASP.NETMVC
- Aspire 框架預覽版釋出,使雲原生開發和運維更加簡單框架運維
- C# Post 模擬表單提交C#
- 如何避免表單的重複提交?
- 事務單獨提交和
- pbootcms提交留言、提交自定義表單時取消驗證碼boot
- 1.4 基於OGG單表到分庫分表資料同步場景
- ASP.NET MVC 反射例子ASP.NETMVC反射
- ASP.NET MVC下使用AngularJs語言(六):獲取下拉選單的value和TextASP.NETMVCAngularJS
- Android 13 首個開發者預覽版到來Android