web-dev-qa-db-ja.com

DataAnnotations:オブジェクトグラフ全体の再帰的な検証

DataAnnotation属性が散在しているオブジェクトグラフがあります。オブジェクトの一部のプロパティは、それ自体が検証属性を持つクラスなどです。

次のシナリオでは:

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; }
}

Employeeの値を指定せずにAddressPostalCodeを検証しようとすると、例外が欲しい(そして期待される)が、何も得られない。以下がその方法です。

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には、他にどのようなオプションがありますか再帰的に

事前に感謝します。

50
Neil Barnwell

私の答えはここに入れるには長すぎたので、ブログの投稿に変えました:)

DataAnnotationsを使用した再帰的な検証

このソリューションは、現在使用しているのと同じ基本的な方法を使用して、再帰的な検証を実現する方法を提供します。

52
Josh

オプトイン属性アプローチの代替手段を次に示します。これはオブジェクトグラフを適切にトラバースし、すべてを検証すると信じています。

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/

また、このソリューションを更新して、循環オブジェクトグラフを処理しました。フィードバックをお寄せいただきありがとうございます。

36
manu08