【原文地址】ASP.NET MVC 2: Model Validation
【原文發表日期】 Friday, January 15, 2010 4:14 AMweb
【除了寫博客外,我如今還使用Twitter發短貼和共享連接。請經過twitter.com/scottgu跟隨我。】正則表達式
這是我針對即將發佈的ASP.NET MVC 2所撰寫的貼子系列的第二篇,這個博客貼子將討論 ASP.NET MVC 2中一些驗證方面的改進。數據庫
對用戶輸入的驗證以及強制業務規則/邏輯是大多數web應用的核心需求。ASP.NET MVC 2包含了一堆新的特性,顯著地簡化了對用戶輸入的驗證以及在模型/視圖模型中對驗證邏輯的強行實施。這些特性是這樣設計的,驗證邏輯老是在服務器上執行的,也能夠選擇在客戶端經過JavaScript來執行。ASP.NET MVC 2中的驗證設施和特性這般設計,以便:安全
1) 開發人員能夠輕易地利用內置於.NET框架中的DataAnnotation驗證支持。DataAnnotation提供了一個很是簡便的方式,使用最少的代碼在對象和屬性上用聲明的方式添加驗證規則。服務器
2) 開發人員能夠集成他們本身的驗證引擎,或者利用現有的驗證框架,象Castle驗證器或EntLib驗證庫。ASP.NET MVC 2的驗證特性是設計來在利用新的 ASP.NET MVC 2的驗證設施(包括客戶端驗證,模型綁定驗證等等)的同時,簡化任何類型的驗證架構的插入的。架構
這意味着,在常見的應用場景中啓用驗證是極其容易的,同時對更高級的場景則還能保持極好的靈活性。mvc
讓咱們在ASP.NET MVC 2中來全程示範一個簡單的CRUD場景,利用新的內置DataAnnotation驗證支持。具體來講,讓咱們來實現一個「Create」表單來容許用戶輸入朋友的數據:app
咱們想要確保在保存到數據庫以前,輸入的信息是合法的,若是不合法,就顯示合適的錯誤消息:框架
我 們想要使得這個驗證同時在服務器端和客戶端(經過 JavaScript)發生。咱們還想要確保咱們的代碼遵照DRY原則(Don't Repeat Yourself,不重複本身),意味着咱們應該只在一處實施驗證規則,而後使得咱們的控制器,action方法和視圖來兌現這個承諾。asp.net
在下面,我將使用VS 2010,用ASP.NET MVC 2來實現上面的場景。你也可使用VS 2008及ASP.NET MVC 2來實現徹底同樣的場景。
咱們首先在一個新的ASP.NET MVC 2項目中加一個簡單的「Person」類,象下面這樣:
它有四個屬性(是用C#的自動屬性支持實現的, 在VS 2010中VB也支持自動屬性了,哎!)。
而後在項目中加一個 「FriendsController」 控制器類,呈示2個 「Create」 action方法。第一個action方法是在對/Friends/Create URL的HTTP-GET請求進來時調用的,它會顯示一個空白的表單,用來輸入我的數據。第二個action方法是在對/Friends/Create URL的HTTP-POST請求進來時調用的。它會將提交的表單輸入映射到一個Person對象,覈實沒有綁定錯誤發生,若是是合法的,最終會將數據保存 到數據庫中去(在本教程的後面咱們會實現相關的數據庫工做)。若是提交的表單輸入是不合法的,該action方法會從新顯示帶有錯誤的表單:
在實現了控制器以後,能夠在Visual Studio中在其中一個action方法中右擊,選擇 「添加視圖」命令, 這會調出 「添加視圖」 對話框。選擇自動生成傳入對象爲Person的「Create」視圖:
而後Visual Studio會在咱們項目的\Views\Friends\目錄中,生成一個含有框架代碼(scaffolded)的Create.aspx視圖文件。注意下面,它利用了ASP.NET MVC 2中新的強類型HTML輔助方法(促成了更好的intellisense和編譯時檢查支持):
如今,當咱們運行該應用,訪問 /Friends/Create URL時,咱們將獲得一張能夠輸入數據的空白表單:
但,由於咱們尚未在應用中實現任何驗證,誰也沒法阻止咱們在表單中鍵入假的輸入,將其提交到服務器去。
如今,讓咱們來更新應用,執行一些基本的輸入驗證規則。咱們將在咱們的Person模型對象上實現這些規則,而不是在控制器或視圖中實現。在Person對象上實現這些規則的好處是,這將確保這些驗證在應用中任何使用Person對象的場景中都會被執行(例如,若是後來添加了編輯場景的話)。這將幫助確保咱們將代碼保持DRY,避免在多處重複這些規則。
ASP.NET MVC 2 容許開發人員輕鬆地在模型或視圖模型類上添加聲明式驗證特性,而後ASP.NET MVC在應用中實施模型綁定操做時,這些驗證規則就會被自動執行。爲看其例子,讓咱們更新Person類,在其中加幾個驗證特性。這麼作,在文件的頂部加 一個對「System.ComponentModel.DataAnnotations」命名空間的 「using」 語句,而後在Person的屬性上飾於[Required], [StringLength], [Range], 和 [RegularExpression] 驗證特性(這幾個特性都是在那個命名空間中實現的):
注: 在上面咱們明式指定了錯誤信息字符串,你也能夠在資源文件中定義它們,或者按進來的用戶的語言/文化作本地化,你能夠在這裏瞭解如何本地化驗證錯誤消息。
既然咱們加了驗證特性到Person類上,讓咱們來從新運行咱們的應用,看在鍵入假的數值,將其提交回服務器時會發生什麼:
注意上面咱們的應用如今有一個蠻好的出錯體驗了。帶不合法輸入的文本元素以紅色高亮顯示,咱們指定的驗證錯誤消息也顯示給了用戶。表單還保留用戶原先輸入的數據,這樣他們不用從新填寫什麼。但,你也許會問,怎麼會是這樣?
要理解這個行爲,讓咱們看一下處理咱們表單的POST場景的Create action方法:
在 咱們的HTML表單被提交回服務器時,上面的方法就會被調用。由於該action方法接受一個「Person」 對象爲參數,ASP.NET MVC會建立一個Person對象,自動地將進來的表單輸入數值映射到該對象上。做爲該過程的一部分,ASP.NET MVC還會檢查該Person對象上的DataAnnotation驗證特性是否合法。若是一切都合法,那麼咱們代碼中的 ModelState.IsValid檢查就會返回真值,在這種情形下,咱們(最終)將把該Person對象保存到數據庫中,而後從新定向回到主頁上去。
但若是Person對象上有任何驗證錯誤的話,咱們的action方法就會以該不合法Person對象的數據從新顯示錶單,這是經過上面代碼片斷中最後一行代碼實現的。
然 後,錯誤消息就會顯示在咱們的視圖中,由於咱們的Create表單在每個<%= Html.TextBoxFor() %>輔助方法的調用旁邊都有一個<%= Html.ValidationMessageFor() %>輔助方法調用。Html.ValidationMessageFor() 輔助方法會針對傳入視圖的任何不合法的模型屬性輸出合適的錯誤消息:
這個模式/方式有一個好處,就是很是容易配置,它還容許咱們輕鬆地添加或改變咱們Person類上的驗證規則,而沒必要改變控制器或視圖中的任何代碼。這個在一個地方指定驗證規則,而後在全部的地方都會被承諾和遵照的能力,容許咱們以最少的努力快速地發展咱們的應用和規則,而且將代碼保持在很是DRY的程度。
目前咱們的應用只能作服務器端的驗證,這意味着咱們的終端用戶須要將表單提交到服務器才能看到任何驗證錯誤消息。
ASP.NET MVC 2的驗證架構中同樣很是酷的東西是,它同時支持服務器端 和 客戶端驗證。爲啓用這個功能,咱們要作的就是在視圖中添加2個 JavaScript引用,編寫一行代碼:
在咱們添加了這三行後,ASP.NET MVC 2 就會使用咱們加到Person類上的驗證元數據,爲咱們鏈接好客戶端JavaScript驗證邏輯。這意味着,當用戶使用tab鍵跳出一個不合法的輸入元素時,就會獲得瞬時的驗證錯誤。
要在咱們的朋友應用中看客戶端JavaScript支持的實戰例子的話,讓咱們從新運行應用,在前三個文本框中填入合法的數值,而後嘗試點擊「Create(建立)」。注意,咱們沒必要訪問服務器就會獲得遺漏值的瞬時錯誤消息:
若是咱們輸入一些不是合法的email的字符話,錯誤消息就會瞬時從「Email Required (Email是個必需值)」 變爲 「Not a valid email (email不合法)」(這是咱們將規則加到Person類上時指定的錯誤消息):
在輸入一個合法的email時,錯誤消息就是瞬時消失,文本框背景色也會恢復到正常的狀態:
好事是,咱們沒必要編寫本身的任何定製JavaScript就能啓用上面的驗證邏輯。咱們的驗證代碼仍是那麼DRY,咱們能夠在一個地方指定規則,而後在整個應用中獲得執行,同時在客戶端和服務器端。
注意,爲安全的緣由,服務器端驗證規則老是執行的,即時你啓用了客戶端支持。這避免黑客嘗試繞過客戶端規則,哄騙攻擊(spoof)你的服務器。
ASP.NET MVC 2中的客戶端JavaScript驗證支持可與你在ASP.NET MVC應用中使用的任何驗證框架/引擎協做,它並不要求你使用 DataAnnotation 驗證方式,全部的基礎設施是獨立於 DataAnnotation的,能夠與Castle驗證器, EntLib驗證應用塊,或你選擇使用的任何定製驗證方案協做使用。
若是你不想使用咱們的客戶端JavaScript文件,你也能夠將其替換成jQuery驗證插件,而使用那個庫。 ASP.NET MVC Futures下載還包括針對ASP.NET MVC 2服務器端驗證框架啓用jQuery驗證的支持。
.NET 框架中的System.ComponentModel.DataAnnotations命名空間包括了衆多可爲你所用的內置驗證特性。咱們在上面的例子中 使用了其中的四個:[Required], [StringLength], [Range], 和 [RegularExpression]。
你 也能夠定義本身的定製驗證特性,而後應用它們。你能夠經過繼承自System.ComponentModel.DataAnnotations命名空間中 的ValidationAttribute基類,定義徹底定製的特性。或者,你也能夠選擇繼承自任何現有的驗證特性,若是你只想要擴展它們的基本功能的 話。
例如,爲幫助清理咱們Person類中的代碼,咱們也許想要建立一個新的[Email]驗證特性,將檢查合法email的正則表達 式封裝起來。要這麼作的話,咱們只要象這樣繼承自RegularExpressionAttribute基類,而後用合適的email正則表達式調用 RegularExpressionAttribute基類的構造器:
而後將Person類更新成使用咱們新的[Email]驗證屬性,換掉咱們先前使用的正則表達式,這使得咱們的代碼更乾淨,封裝也更好:
在建立定製的驗證特性時,你還能夠指定在服務器端以及在客戶端經過JavaScript執行的驗證邏輯。
除 了建立可施用於對象上個別屬性的驗證特性外,你還能夠將驗證特性施用於類的層次,這容許你對一個對象中的多個屬性實施驗證邏輯。要看實戰例子的話,你能夠 參閱包含在默認ASP.NET MVC 2應用項目模板中AccountModels.cs/vb文件中的「PropertiesMustMatchAttribute」 定製特性(在VS 2010中作 文件->新ASP.NET MVC 2 Web項目,而後查詢該類)。
如今讓咱們來實現將朋友數據保存到數據庫所需的邏輯。
至 此,咱們只用了平白的(plain-old)C#類(有時稱爲「POCO」 類, 即 「plain old CLR (or C#) object」)。咱們可使用的一個方案是,編寫一些單獨的持久代碼,將這咱們已經編寫好的現有類映射到數據庫去。目前象NHibernate這樣的對 象關係映射(Object relational mapping - ORM)方案很是地好支持這樣的POCO/PI風格的映射。隨.NET 4發佈的ADO.NET實體框架(Entity Framework - EF)也支持POCO / PI映射,並且就象NHibernate,EF也能啓用以「只用代碼(code only)」的方式(沒有映射文件,也不須要設計器)定義持久性映射的能力。
若是咱們的Person對象以這種方式映射到數據庫的話,咱們不用對Person類作任何改動,也不用改動任何驗證規則,它還會繼續無缺地工做。
但假如咱們要使用圖形工具來作ORM映射的話,怎麼辦?
今天使用Visual Studio的許多開發人員並不編寫他們本身的ORM映射/持久邏輯,而是使用Visual Studio中內置的設計器來幫助管理這樣的映射邏輯。
使 用DataAnnotation(或者任何其餘形式的基於特性的驗證)時一個常常問起的問題是,「若是你手頭的模型對象是由GUI設計器建立/維護的話, 你該如何施用這些特性?」。例如,假如與相似咱們至此爲止一直在使用的POCO風格的Person類不一樣,咱們而是在Visual Studio中經過象LINQ to SQL 或 ADO.NET EF設計器這樣的GUI映射工具定義/維護咱們的Person類的話,該怎麼辦呢:
上 面是一張屏幕截圖,展現了在VS 2010中使用ADO.NET EF設計器定義的一個Person類。上方的窗口定義了Person類,下方的窗口展現了該類的屬性是如何映射到數據庫中的「People」表的映射編輯 器。當你在設計器上點擊保存時,它會自動爲你在項目中生成一個Person類。這很棒,但每次你作了改動,點擊保存時,它就會從新生成 Person 類,這會致使你在對象上面聲明的任何驗證特性的丟失。
將 額外的基於特性的元數據(象驗證特性)施加到由VS設計器自動生成/維護的類的一個方法是,採用一個咱們稱之爲「夥伴類(buddy classes)」的技術。基本上來講,你建立另一個類,包含你的驗證特性和元數據,而後經過將 「MetadataType」特性施加到一個與工具生成的類一塊兒編譯的partial類上,將其與由設計器生成的類鏈接起來。例如,若是咱們想要將咱們前 面用到的驗證規則施加到由LINQ to SQL 或 ADO.NET EF設計器維護的Person類上,咱們能夠更新咱們的驗證代碼,使其存在於一個單獨的「Person_Validation」類上,使用象下面這樣的代 碼將其鏈接到由VS建立的「Person」類上:
上面的作法沒有純粹的POCO方法那麼優雅,但其好處是,能夠用於Visual Studio中任何工具或設計器生成的代碼。
最後一步 – 將Friend保存到數據庫中
最後一步,不論是否採用了POCO或工具生成的Person類,是將合法的朋友數據保存到數據庫中去。
這隻要求咱們用三行代碼將FriendsControlle類中的 「Todo」佔位語句替換掉,這三行代碼將新朋友保存到數據庫。下面是整個FriendsController類的完整代碼(使用了ADO.NET EF作數據庫持久化):
如今,當咱們訪問 /Friends/Create URL時,咱們能夠輕鬆地添加新人到咱們的朋友數據庫中去:
對全部數據的驗證都是同時在客戶端和服務器端執行的。咱們能夠輕易地在一個地方添加/修改/刪除驗證規則,而由整個應用中的全部的控制器和視圖來執行這些規則。
ASP.NET MVC 2極大地簡化了web應用的驗證集成。它倡議一種基於模型的驗證方式,容許你將你的應用保持DRY,幫助確保驗證規則在整個應用中保持一致。 ASP.NET MVC 2中內置的DataAnnotation支持,本來就使得對常見的驗證場景的支持很是容易。並且,ASP.NET MVC 2驗證設施中的擴展性支持容許你支持更大範圍的更高級的驗證場景,能夠插入任何現有的或者定製的驗證框架/引擎。
但願本文對你有所幫助。