在自定義 ViewModel 中重用驗證屬性
當我開始使用xVal進行客戶端驗證時,我只實現了將域模型對像用作視圖模型或視圖模型中這些對象的嵌入實例的操作方法。
這種方法在大多數情況下都可以正常工作,但在某些情況下,視圖只需要顯示和回發模型屬性的子集(例如,當使用者想要更新他的密碼,而不是他的其他配置文件數據時) .
一個(醜陋的)解決方法是在表單上為表單上不存在的每個屬性設置一個隱藏的輸入欄位。
顯然這裡的最佳實踐是創建一個自定義視圖模型,它只包含與視圖相關的屬性並通過Automapper填充視圖模型。因為我只傳輸與視圖相關的數據,所以它更乾淨,但它遠非完美,因為我必須重複域模型對像上已經存在的相同驗證屬性。
理想情況下,我想通過 MetaData 屬性將域模型對象指定為元類(這通常也稱為“夥伴類”),但這不起作用,因為當元數據類具有以下屬性時 xVal 拋出不存在於視圖模型上。
有什麼優雅的解決方法嗎?我一直在考慮破解 xVal 原始碼,但也許到目前為止我還忽略了其他一些方法。
謝謝,
阿德里安
**編輯:**隨著 ASP.NET MVC 2 的到來,這不僅是一個與驗證屬性相關的問題,而且它也適用於編輯器和顯示屬性。
這就是為什麼您的輸入螢幕不應該與您的模型緊密耦合的典型原因。這個問題實際上每月會在 MVC 標籤上彈出 3-4 次。如果我能找到上一個問題並且這裡的一些評論討論很有趣,我會欺騙。;)
您遇到的問題是您試圖將模型的兩個不同驗證上下文強制轉換為在大量場景下失敗的單個模型。最好的例子是註冊一個新使用者,然後讓管理員稍後編輯使用者欄位。您需要在註冊期間驗證使用者對象的密碼,但您不會向編輯使用者詳細資訊的管理員顯示密碼欄位。
繞過這些的選擇都是次優的。我現在已經為 3 個項目解決了這個問題,並且實施以下解決方案從來都不是乾淨的,而且通常令人沮喪。我將嘗試變得務實,忘記所有其他人正在進行的 DDD/db/model/hotnessofthemonth 討論。
1) 多視圖模型 擁有幾乎相同的視圖模型違反了 DRY 原則,但我覺得這種方法的成本非常低。通常違反 DRY 會增加維護成本,但恕我直言,這方面的成本是最低的,而且並不多。假設您不會經常更改 LastName 欄位的最大字元數。
2) 動態元數據 MVC 2 中有用於為模型提供您自己的元數據的鉤子。使用這種方法,您可以根據目前 HTTPRequest 以及因此 Action 和 Controller 來提供用於提供元數據的任何內容來排除某些欄位。我已經使用這種技術建構了一個數據庫驅動的權限系統,該系統進入數據庫並告訴 DataAnnotationsMetadataProvider 的子類排除儲存在數據庫中的基於屬性的值。
這種技術在 atm 上執行良好,但唯一的問題是使用
UpdateModel(). 為了解決這個問題,我們創建了一個SmartUpdateModel()方法,該方法也進入數據庫並自動生成排除字元串$$ $$數組,以便不驗證任何不允許的欄位。我們當然出於性能原因記憶體了它,所以它還不錯。 只是想重申我們使用
$$ ValidationAttributes $$在我們的模型上,然後在執行時用新規則取代它們。最終結果是,
[Required]如果使用者沒有訪問權限,則不會驗證 User.LastName 欄位。 3) Crazy Interface Dynamic Proxy Thing 我嘗試的最後一個技術是使用 ViewModel 的介面。IAdminEdit最終結果是我有一個繼承自和之類的介面的 User 對象IUserRegistration。IAdminEdit 和 IUserRegistration 都將包含 DataAnnotation 屬性,這些屬性執行所有特定於上下文的驗證,例如帶有介面的 Password 屬性。這需要一些技巧,並且比其他任何事情都更像是一種學術練習。2 和 3 的問題是需要自定義 UpdateModel 和 DataAnnotationsAttribute 提供程序以了解此技術。
我最大的絆腳石是我不想將整個使用者對象發送到視圖,所以我最終使用動態代理來創建執行時實例
IAdminEdit現在我明白這是一個非常特定於 xVal 的問題,但是像這樣的動態驗證的所有道路都會導致內部 MVC 元數據提供程序的定制。由於所有元數據的東西都是新的,在這一點上沒有什麼是乾淨或簡單的。自定義 MVC 的驗證行為所要做的工作並不難,但需要深入了解所有內部結構的工作原理。