原文連結:http://msdn.microsoft.com/zh-cn/downloads/ff393634.aspx
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的驗證設施(包括用戶端驗證,模型繫結驗證等等)的同時,簡化任何類型的驗證架構的插入的。
這意味著,在常見的應用情境中啟用驗證是極其容易的,同時對更進階的情境則還能保持極好的靈活性。
使用ASP.NET MVC 2 和 DataAnnotation來啟用驗證
讓我們在ASP.NET MVC 2中來全程示範一個簡單的CRUD情境,利用新的內建DataAnnotation驗證支援。具體來說,讓我們來實現一個“Create”表單來允許使用者輸入朋友的資料:
我們想要確保在儲存到資料庫之前,輸入的資訊是合法的,如果不合法,就顯示合適的錯誤訊息:
我們想要使得這個驗證同時在伺服器端和用戶端(通過 JavaScript)發生。我們還想要確保我們的代碼遵守DRY原則(Don't Repeat Yourself,不重複自己),意味著我們應該只在一處實施驗證規則,然後使得我們的控制器,action方法和視圖來兌現這個承諾。
在下面,我將使用VS 2010,用ASP.NET MVC 2來實現上面的情境。你也可以使用VS 2008及ASP.NET MVC 2來實現完全一樣的情境。
第一步: 實現FriendsController (一開始沒有驗證)
我們首先在一個新的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時,我們將得到一張可以輸入資料的空白表單:
但,因為我們還沒有在應用中實現任何驗證,誰也無法阻止我們在表單中鍵入假的輸入,將其提交到伺服器去。
第二步: 使用DataAnnotation來啟用驗證
現在,讓我們來更新應用,執行一些基本的輸入驗證規則。我們將在我們的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驗證的支援。
第四步: 建立自訂的[Email]驗證特性
.NET架構中的System.ComponentModel.DataAnnotations命名空間包括了眾多可為你所用的內建驗證特性。我們在上面的例子中使用了其中的四個:[Required], [StringLength], [Range], 和 [RegularExpression]。
你也可以定義自己的定製驗證特性,然後應用它們。你可以通過繼承自System.ComponentModel.DataAnnotations命名空間中的ValidationAttribute基類,定義完全定製的特性。或者,你也可以選擇繼承自任何現有的驗證特性,如果你只想要擴充它們的準系統的話。
例如,為協助清理我們Person類中的代碼,我們也許想要建立一個新的[Email]驗證特性,將檢查合法email的Regex封裝起來。要這麼做的話,我們只要象這樣繼承自RegularExpressionAttribute基類,然後用合適的emailRegex調用RegularExpressionAttribute基類的構造器:
然後將Person類更新成使用我們新的[Email]驗證屬性,換掉我們先前使用的Regex,這使得我們的代碼更乾淨,封裝也更好:
在建立定製的驗證特性時,你還可以指定在伺服器端以及在用戶端通過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.NETEntity Framework(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驗證設施中的擴充性支援允許你支援更大範圍的更進階的驗證情境,可以插入任何現有的或者定製的驗證架構/引擎。