摘要:用EF Code First和ASP.Net MVC3進行類級別模型驗證
[原文發表位置] Class-Level Model Validation with EF Code First and ASP.NET MVC 3
[原文發表時間] December 10, 2010 1:05 AM
本周稍早時資料組發佈了Entity Framework Code-First (EF Code-First) 新的CTP5版本。
我幾天前的部落格中談到CTP5版中所引入的一些新改進。支援對模型上資料標記屬性(Data Annotation Validation attributes)的自動強制驗證是其中之一。它讓你很容易地在模型層實現屬性層驗證邏輯。
你能應用驗證屬性(validation attribute)—— 如.NET 4內建的[Required],[Range]—— [RegularExpression] 到你的模型類別別中,從而保證儲存到資料庫之前模型屬性的有效性得到驗證。你也能生成你自己的客制驗證屬性像這個比較酷的[CreditCard]validator)並將他們透過EF Code First自動強制實施。這是一個在你的模型中驗證屬性值的簡單方法。我在我之前的部落格展示了這種操作的一些範例程式碼。
使用IValidatableObject實施 Class-level 模型驗證
資料註解屬性供了一種簡單的方法來驗證你的模型類別中的單個屬性值。
有些人問道:是否EF Code First也支援在模型對像上應用 Class-Level 驗證方法,只管驗證規則而不需要涉及很多屬性值? 答案是肯定的——你有一個很簡單的方法來實現:在你的模型類別中實現IValidatableObject介面。
IValidatableObject.Validate()方法
下面是一個在Product模型類別中使用IvalidatableObject介面(包含於.NET4的System.ComponentModel.DataAnnotaions命名空間內)實現兩個客制驗證規則的範例。這兩個規則保證:
- 如果產品(product)處於斷貨狀態,新單品(Unit)不能被訂購。
- 如果庫存超過100 Unit,新單品(Unit)不能被訂購。
我們將透過實現我們的Product 類別中的IValidatableObject介面和它的Validate()方法來強制實施這些商業規則,像這樣:
IValidatableObject.Validate()方法能應用涉及多個屬性的驗證規則,並傳回多方個驗證錯誤。每個傳回的驗證結果都提供一個錯誤消息和一個導致驗證衝突的候選屬性名稱列表(這對顯示UI內的錯誤訊息非常有用)。
強制自動驗證
在實現了IvalidatableObject介面的模型對像被保存的時候,EF Code First(自CTP5起)現在會自動呼叫Validate()方法。你無需寫任何程式碼來實現它——現在這個是預設支援的。
這個新支援意味著下面違反了上面所說的一條商業規則的程式碼將在我們呼叫Northwind.DBContext的 SaveChanges() 方法的時候自動拋出一個異常(並中止事務)。
除了相應地處理驗證異常之外,EF Code First還允許你主動檢查驗證錯誤。自CTP5開始, 你能呼叫DbContext基底類別的GetValidationErrors()方法來傳回一列被處理模型對象中的驗證錯誤。 GetValidationErrors()將傳回所有驗證錯誤——不管他們是透過資料標記屬性(DataAnnotation Attribute)還是透過IValidatableObjectValidate()實作生成的。
以下是一個在嘗試呼叫 SaveChanges() 前使用 GetValidationErrors() 方法主動檢查錯誤的範例:
ASP.Net MVC3 和 IValidatableObject
對與ASP.NET MVC的模型繫結結構一起使用的模型對象,ASP.NET MVC2支援其資料標記屬性的自動強制實施。 ASP.Net MVC3走的更遠,它還支援IValidatableObject介面。在有驗證錯誤的時候,這個對模型驗證的綜合支援使顯示表單內的錯誤訊息變得簡單。
為了Demo這個操作,讓我們研究一個簡單的允許用戶生成新product的Create視窗:
我們能使用一個包含下面2個方法的ProductController類別來實現上面的兩個Create功能:
第一個Create()方法實現一種/Product/Create URL來處理HTTP-GET請求,並顯示HTML表單以供填寫。第二個Create()方法實現另一種/Product/Create URL來處理HTTP-Post請求——它取出提交的表單資料,保證它的有效性,如果有效的話將其保存在資料庫內。 如果驗證有問題,它會重新顯示表單和它提交的值。
我們的「Create」視圖(描述表單的)的Razor畫面模板類似下面這樣:
在上面的控制器畫面實作的重點之一是我們沒有寫任何驗證邏輯在裡面。驗證邏輯和商業規則完全在我們的模型層實現,而ProductsController只透過簡單地檢查它是否有效——透過呼叫ModelStateIsValid Helper 方法 ——來決定是去試著保存修改還是重新顯示帶有錯誤的表單。我們的 View 呼叫的 Html.ValidationMessageFor()Helper方法只簡單地顯示我們的Product模板的資料標記和IValidatableObject.Validate()方法所傳回的錯誤訊息。
我們能透過在表單中輸入不合法資料並嘗試提交以重現以上場景。
注意上面當我們點 Create 按鈕的時候我們是怎樣得到一個錯誤訊息的。這是因為我們選中了 Discontinued 復選框的同時輸入了一個UnitsOnOrder值(所以違反了我們的商業規則中的一條)。
你可能會問:ASP.Net MVC如何知道要在UnitsOnOrder文字框旁反白顯示錯誤訊息的?這是因為ASP.NET MVC 3在實現模型繫結的時候支援IvalidatableObject介面,它會傳回其驗證失敗的錯誤訊息。
我們的產品模型類別中的商業規則指定我們的商業規則被違反的時候 UnitsOnOrder 屬性必須被反白顯示。
因為上面的屬性名提示,所以我們的Html.ValidationMessageFor()helper方法知道要在UnitsOnOrder編輯框旁邊顯示商業規則錯誤訊息:
保持程式碼「乾燥」(DRY:Don't repeat yourself)
ASP.NET MVC和EF Code First使你能將驗證和商業規則置於同一個地方(在你的模型層中),防止它們溜到你的控制器和 View 裡去。
在模型層放置驗證邏輯可以幫助防止你在往應用程式中添加更多的控制器和 View 的時候重複驗證/商業邏輯。它允許你在一個地方(你的模型層中)快速更改你的商業規則/驗證邏輯,並立刻在你應用程式中所有的控制器/View 中體現出來。這讓你的程式碼乾淨,容易維護,並能在將來很容易進化和升級。
總結
EF Code First(自CTP5開始)現在支援資料標記和IValidatableObject介面。這允許你能很容易地添加驗證和商業規則到你的模型中,在每次有人試圖將它們的改動與資料庫同步的時候,EF將自動地保證它們的強制實施。
ASP.Net MVC 3現在也支援資料標記和IValidatableObject, 從而讓你能在你的EF Code First模型層更容易地使用它們,也使你的網路層的控制器/View 也都獲得自動支援。這使生成乾淨和易維護的應用程式變得更加簡單。
你不是必須使用資料標記或者IValidatableObject來執行你的驗證 /商業邏輯 。你總能加入你自己的客制驗證和/或其他你想要的進階驗證框架/模式。但是對很多應用程式來說,這個能高效率生成解決方案的內建支援很可能就已經足夠。
希望這些對您有所幫助。