2010-02-15 29 views
2

我一直在研究一個使用xVal的服務器端驗證和數據註釋的應用程序。我們最近遇到了錯誤,其中驗證消息對於有多個驗證的字段而言是不可預測的,如果該字段爲空(例如,需要電子郵件地址,但無法驗證有效性),則驗證消息可能會失敗。如何確定不可預測的LINQ查詢結果的來源?

假設我需要只返回一個驗證錯誤,我添加了一個方法,我們的驗證亞軍,以實現這一目標(UPDATE:見編輯在底部的確切方法):

public static IEnumerable<ErrorInfo> GetFirstErrors<T>(object instance) where T : ValidationAttribute 
    { 
     return from prop in TypeDescriptor.GetProperties(instance).Cast<PropertyDescriptor>() 
       from attribute in prop.Attributes.OfType<T>().Take(1) 
       where !attribute.IsValid(prop.GetValue(instance)) 
       select new ErrorInfo(prop.Name, attribute.FormatErrorMessage(string.Empty), instance); 
    } 

我還設置了一個簡單的測試方法NUnit的驗證:

private class FirstErrorValidationTest 
    { 
     [RequiredValueValidator(ErrorMessage = "This field is required"), StringLength(50)] 
     public string FirstName { get; set; } 

     [RequiredValueValidator(ErrorMessage = "This field is required"), StringLength(50)] 
     public string LastName { get; set; } 

     [RequiredValueValidator(ErrorMessage = "This field is required"), EmailAddressValidator, StringLength(50)] 
     public string EmailAddress { get; set; } 
    } 

    [Test] 
    public void Assert_GetFirstErrors_Gets_First_Listed_Validation_Attribute_Error_Messages() 
    { 
     FirstErrorValidationTest test = new FirstErrorValidationTest() 
     { 
      FirstName = "", 
      LastName = "", 
      EmailAddress = "" 
     }; 

     var errors = DataAnnotationsValidationRunner.GetFirstErrors(test); 

     Assert.AreEqual(3, errors.Count()); 

     foreach (var error in errors) 
      Assert.IsTrue(error.ErrorMessage.Contains("required")); 
    } 

的問題是,這個測試的輸出是非常難以預測的。有時它會通過,有時它會返回一兩個錯誤,有時甚至沒有。這是我的LINQ查詢,我的測試,還是兩者的問題?

編輯:偉大的點粘貼在一個稍微不同的方法;這裏實際上是被擊中的一個:

public static IEnumerable<ErrorInfo> GetFirstErrors(object instance) 
    { 
     return from prop in TypeDescriptor.GetProperties(instance).Cast<PropertyDescriptor>() 
       from attribute in prop.Attributes.OfType<ValidationAttribute>().Take(1) 
       where !attribute.IsValid(prop.GetValue(instance)) 
       select new ErrorInfo(prop.Name, attribute.FormatErrorMessage(string.Empty), instance); 
    } 
+0

這是如何編譯? 'GetFirstErrors'需要一個你從未指定的類型參數'T',無論是顯式的還是隱式的。 – 2010-02-15 14:30:12

+0

對不起!我粘貼了適當的方法。 – 2010-02-15 15:35:36

回答

2

擺脫Take(1)的。我懷疑空字符串正在通過Required測試。如果你發生得到的,而不是長度驗證,測試通過。

+0

Take(1)電話絕對是罪魁禍首。是否沒有辦法在屬性選擇上進行任何形式的隱式排序或優先級排序(即,檢查其他任何其他字段的屬性)? – 2010-02-15 20:50:02

+0

這是可能的,但由於這是一個單元測試,爲什麼?你不應該檢查測試數據的所有屬性嗎? – 2010-02-15 21:20:26

+0

我絕對同意,但是什麼樣的方法可以更好地執行每個字段顯示一個驗證錯誤的全局規則(並支持必需字段失敗)?它看起來像模型狀態錯誤在字典中彙總以供視圖使用,所以如果選擇是任意的,似乎我們無法預測首先會顯示什麼錯誤。 – 2010-02-15 21:32:25

0

嘗試使用

var errors = DataAnnotationsValidationRunner.GetFirstErrors(test).ToArray(); 
+0

我給了這個嘗試,仍然得到不可預知的結果。我注意到,當我離開NUnit時,清理/重新編譯,然後再次運行它是最容易發生變化的時候。 – 2010-02-15 15:43:36