2011-10-05 84 views
42

我有一個灑有DataAnnotation屬性的對象圖,其中對象的某些屬性是本身具有驗證屬性的類,等等。DataAnnotations:遞歸驗證整個對象圖

在以下情形:

public class Employee 
{ 
    [Required] 
    public string Name { get; set; } 

    [Required] 
    public Address Address { get; set; } 
} 

public class Address 
{ 
    [Required] 
    public string Line1 { get; set; } 

    public string Line2 { get; set; } 

    [Required] 
    public string Town { get; set; } 

    [Required] 
    public string PostalCode { get; set; } 
} 

如果我嘗試驗證的EmployeeAddress沒有價值PostalCode,那麼我想(和期望)例外,但我得到沒有。下面是我如何做它:

var employee = new Employee 
{ 
    Name = "Neil Barnwell", 
    Address = new Address 
    { 
     Line1 = "My Road", 
     Town = "My Town", 
     PostalCode = "" // <- INVALID! 
    } 
}; 

Validator.ValidateObject(employee, new ValidationContext(employee, null, null)); 

我有什麼其他的選擇與Validator,以確保所有的屬性進行驗證遞歸

非常感謝提前。

回答

47

我的回答得到了太長時間放在這裏,所以我把它變成了博客文章:)

Recursive Validation Using DataAnnotations

該解決方案爲您提供了一個方式使用您使用的是相同的基本方法來實現遞歸驗證現在。

+1

+ 1爲好的解決方案 – Jehof

+0

不錯,但收集呢?能夠驗證諸如「公共IList

地址」這樣的屬性是非常棒的。無論如何,感謝您的解決方案。 – altso

+0

該屬性不爲我評估。 –

23

下面是opt-in屬性方法的替代方案。我相信這將正確地遍歷對象圖並驗證一切。

public bool TryValidateObjectRecursive<T>(T obj, List<ValidationResult> results) { 

bool result = TryValidateObject(obj, results); 

var properties = obj.GetType().GetProperties().Where(prop => prop.CanRead 
    && !prop.GetCustomAttributes(typeof(SkipRecursiveValidation), false).Any() 
    && prop.GetIndexParameters().Length == 0).ToList(); 

foreach (var property in properties) 
{ 
    if (property.PropertyType == typeof(string) || property.PropertyType.IsValueType) continue; 

    var value = obj.GetPropertyValue(property.Name); 

    if (value == null) continue; 

    var asEnumerable = value as IEnumerable; 
    if (asEnumerable != null) 
    { 
     foreach (var enumObj in asEnumerable) 
     { 
      var nestedResults = new List<ValidationResult>(); 
      if (!TryValidateObjectRecursive(enumObj, nestedResults)) 
      { 
       result = false; 
       foreach (var validationResult in nestedResults) 
       { 
        PropertyInfo property1 = property; 
        results.Add(new ValidationResult(validationResult.ErrorMessage, validationResult.MemberNames.Select(x => property1.Name + '.' + x))); 
       } 
      }; 
     } 
    } 
    else 
    { 
     var nestedResults = new List<ValidationResult>(); 
     if (!TryValidateObjectRecursive(value, nestedResults)) 
     { 
      result = false; 
      foreach (var validationResult in nestedResults) 
      { 
       PropertyInfo property1 = property; 
       results.Add(new ValidationResult(validationResult.ErrorMessage, validationResult.MemberNames.Select(x => property1.Name + '.' + x))); 
      } 
     } 
    } 
} 

return result; 
} 

最先進的最新代碼: https://github.com/reustmd/DataAnnotationsValidatorRecursive

套餐: https://www.nuget.org/packages/DataAnnotationsValidator/

而且,我已經更新了這個解決方案來處理循環對象圖。感謝您的反饋。

+6

我喜歡這個解決方案,但是當對象圖包含循環時要小心無限循環。 –

+0

@ manu08 ....平平無奇 - 感謝您的時間保存。 – Pakk

+0

上面的代碼示例與git版本相比有一些問題 - 如果您打算實施,那麼絕對[遵循鏈接](https://github.com/reustmd/DataAnnotationsValidatorRecursive/tree/master/DataAnnotationsValidator/DataAnnotationsValidator)這個(或者通過[nuget](https://www.nuget.org/packages/DataAnnotationsValidator/)提供的'Install-Package dataannotationsvalidator'!) – rogersillito