DataAnnotations:递归验证整个对象图

Nei*_*ell 52 .net c# validation recursion data-annotations

我有一个带有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; }
}
Run Code Online (Sandbox Code Playgroud)

如果我尝试来验证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));
Run Code Online (Sandbox Code Playgroud)

我还有哪些其他选项Validator可以确保所有属性都以递归方式验证?

提前谢谢了.

man*_*u08 39

这是选择加入属性方法的替代方法.我相信这将正确地遍历对象图并验证一切.

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;
}
Run Code Online (Sandbox Code Playgroud)

最新代码:https: //github.com/reustmd/DataAnnotationsValidatorRecursive

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

此外,我已更新此解决方案以处理循环对象图.感谢您的反馈.

  • 我喜欢这个解决方案,但是当对象图包含循环时要小心无限循环. (6认同)
  • 与git版本相比,上面的代码示例存在一些问题-因此,如果您希望实现此代码,则可以肯定地[遵循链接](https://github.com/reustmd/DataAnnotationsValidatorRecursive/tree/master/DataAnnotationsValidator/DataAnnotationsValidator) (或通过[nuget](https://www.nuget.org/packages/DataAnnotationsValidator/)使用“ Install-Package dataannotationsvalidator”!) (2认同)

小智 13

您可以扩展默认的验证行为,使您想要验证的类实现该IValidatableObject接口

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

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

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        var results = new List<ValidationResult>();

        Validator.TryValidateObject(Address, new ValidationContext(Address), results, validateAllProperties: true);

        return results;
    }
}

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; }
}
Run Code Online (Sandbox Code Playgroud)

Validator并通过以下方式之一使用该类进行验证

Validator.ValidateObject(employee, new ValidationContext(employee), validateAllProperties: true);
Run Code Online (Sandbox Code Playgroud)

或者

var validationResults = new List<ValidationResult>();
Validator.TryValidateObject(employee, new ValidationContext(employee), validationResults, validateAllProperties: true);
Run Code Online (Sandbox Code Playgroud)