2011-10-05 18 views
42

Tengo un gráfico de objetos salpicado con atributos de anotación de datos, donde algunas propiedades de objetos son clases que tienen atributos de validación, y así sucesivamente.Anotaciones de datos: validando recursivamente un gráfico completo de objetos

En el siguiente escenario:

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

Si trato de validar un Employee 's Address sin valor para PostalCode, entonces me gustaría (y esperan) una excepción, pero me da ninguna. Así es como lo estoy haciendo:

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

¿Qué otras opciones tengo con Validator que aseguraría todas las propiedades son validados de forma recursiva ?

Muchas gracias de antemano.

Respuesta

47

Mi respuesta tiene demasiado tiempo para poner aquí, por lo que la convirtió en una entrada de blog :)

Recursive Validation Using DataAnnotations

La solución le da una forma de lograr la validación recursiva usando el mismo método básico que está utilizando ahora.

+1

+ 1 para una buena solución – Jehof

+0

Bien, pero ¿y las colecciones? Sería genial tener la capacidad de validar propiedades como esta 'public IList

Addresses'. De todos modos, gracias por la solución. – altso

+0

El atributo no se evalúa por mí. –

23

Aquí hay una alternativa al enfoque de atributo de aceptación. Creo que esto atravesará el objeto-gráfico correctamente y validará todo.

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

más arriba-a-fecha de código: https://github.com/reustmd/DataAnnotationsValidatorRecursive

paquete: https://www.nuget.org/packages/DataAnnotationsValidator/

Además, he actualizado esta solución para manejar gráficos de objetos cíclicas. Gracias por la respuesta.

+6

Me gusta esta solución, pero ten cuidado con los bucles infinitos cuando el gráfico de objetos contiene ciclos. –

+0

@ manu08 .... maravilloso, gracias por el tiempo de ahorro. – Pakk

+0

El ejemplo de código anterior tiene algunos problemas en comparación con la versión de git, así que definitivamente [siga el enlace] (https://github.com/reustmd/DataAnnotationsValidatorRecursive/tree/master/DataAnnotationsValidator/DataAnnotationsValidator) si desea implementar esto (o 'Install-Package dataannotationsvalidator' a través de [nuget] (https://www.nuget.org/packages/DataAnnotationsValidator/)!) – rogersillito

Cuestiones relacionadas