2011-10-05 19 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; } 
} 

私はPostalCodeためEmployeeAddress値のないを検証しようとした場合は、その後、私は好き(と期待)例外を、私は何を得ないだろう。ここで私はそれをやっている方法は次のとおりです。

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

いいですが、コレクションはどうですか?この 'public IList

Addresses'のようなプロパティを検証することは素晴らしいことです。とにかく、解決のおかげで。 – altso

+0

この属性は評価されていません。 –

23

オプトインアトリビュートアプローチの代替方法は次のとおりです。私はこれがオブジェクトグラフを適切に横断してすべてを検証すると信じています。

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

関連する問題