2014-02-24 43 views
7

一直試圖將服務器端DataAnnotation驗證合併到我的項目中,並且我發現DataAnnotations有它自己的錯誤類型ValidationException。但是我的問題是,它一次只返回一個驗證錯誤,所以如果3個屬性驗證失敗,只會引發第一個驗證錯誤。我正在尋找一種方法將所有錯誤作爲異常拋出,所以不是通知用戶/開發人員驗證失敗,而是一次性指出哪些屬性/域未通過驗證。返回多個ValidationExceptions

我找到了Validator.TryValidateObject(...)方法,但它只是填充ValidationResults並讓開發人員選擇拋出和異常與否。我目前實現的是遍歷ValidationResults,從中創建一個ValidationExceptions列表,將列表包裝成一個AggregateException,然後在其InnerExceptions中拋出另一個帶有AggregateException的ValidationException。

ValidationContext validationContext = new ValidationContext(entity, null, null); 
List<ValidationResult> validationResults = new List<ValidationResult>(); 

bool isValid = Validator.TryValidateObject(entity, validationContext, validationResults, true); 

if (!isValid) 
{ 
     List<ValidationException> validationErrors = new List<ValidationException>(); 
     foreach (ValidationResult validationResult in validationResults) 
     {  
      validationErrors.Add(new ValidationException(validationResult.ErrorMessage); 
     } 

     throw new ValidationException("Entity validation failed.", new AggregateException(validationErrors)); 
} 

所以基本上,我的問題是:

  1. 是否有一個原因,沒有內置的方式在同一時間拋出多個錯誤?也就是說,我是否缺少DataAnnotation驗證的一些最佳實踐?
  2. 有沒有更好的方法來實現我試圖實現的目標?
  3. 另外...如何將ValidationResult包裝到ValidationException中時包含成員名稱?
+0

我和你有類似的情況,我假設你已經實現了一個體面的解決方案,它是可擴展的? –

回答

0

關於你的第一個問題,「爲什麼不支持X語言」的標準答案只是成本與收益,我相信這裏也適用。人們並不是經常遇到需要拋出多個錯誤的場景......因此,設計和實現C#的人們認爲,C#團隊設計和實現「拋出多個例外」功能所需的時間將花費在爲更多人提供更多益處的功能。

,並考慮成本語言用戶 - 無處不在,你現在有「趕上(例外五)」你不得不做的「抓(IEnumerable的例外)」來代替,然後一個foreach,以防API,它你稱之爲拋出了多個例外。

關於你的第二個問題,我認爲將你的ValidationExceptions與AggregateException相結合,並將聚合設置爲頂級ValidationException的InnerException是一種相當不錯的方式來解決這個問題......但它不是標準的,所以希望那個例外層次結構的「捕捉」方面的人是你與之密切溝通的人。

您也可以考慮將您的ValidationResult集合存儲在ValidationException的Data屬性中。這有點簡單。數據屬性沒有被廣泛使用,但是它存在於像這樣的非標準場景中。

很難說這兩種方法哪一種更好,但我傾向於第一種方法。它比較複雜,但是我認爲如果你在InnerException和AggregateException上構建,那麼任意編碼器發現你所做的事情的可能性要高一點。我的意思是,當你在調試某些東西時,最後一次拋棄了Exception.Data的內容?是的,我也沒有。 :-)

關於你的第三個問題,我想我只是基於ValidationResult的內容構建ValidationException的消息。例如,「成員{0}」無效:{1}「。

0

回答你的第一個問題: 因爲每個驗證屬性都有自己IsValid財產和返回public ValidationResult(string errorMessage, IEnumerable<string> memberNames);驗證結果,你可以從成員名稱的列表獲取成員的名字。所以每個驗證失敗的屬性返回isValid。該實體具有您在實體財產上應用的驗證並不是一個好主意。

回答你的第二個問題: 您可以創建自己的ValidationAttribute列表來驗證實體:

var validationResults = new List<ValidationResult>(); 
var validationAttributes = new List<ValidationAttribute>(); 
validationAttributes.Add(new CustomValidationAttribute(typeof(ClaimValidator), "ValidateClaim")); 
var result = Validator.TryValidateValue(claimObject, 
             new ValidationContext(claimObject, null, null), 
             validationResults, 
             validationAttributes); 

第三個答案: 您可以從ValidationResult得到會員名:

public ValidationResult(string errorMessage, IEnumerable<string> memberNames)