9

DataAnnotations no funciona con la clase buddy. El siguiente código siempre valida verdadero. Por qué ?La validación no funciona cuando uso Validator.TryValidateObject

var isValid = Validator.TryValidateObject (new Customer(), Context, results, true);

y aquí está la clase de amigo.

public partial class Customer 
{ 
    public string Name { get; set; } 
    public int Age { get; set; } 
} 

[MetadataType(typeof(CustomerMetaData))] 
public partial class Customer 
{ 
    public class CustomerMetaData 
    { 
     [Required(ErrorMessage = "You must supply a name for a customer.")]   
     public string Name { get; set; } 
    } 
} 

Aquí hay otro tema con la misma pregunta., Pero no hay respuesta. link text

+0

no estoy Shure acerca de esto, pero creo que no debería nido de las clases. También creo que esto podría hacer que CustomMetaData-class fuera inaccesible sin la palabra clave public-keyword. Intente mover CustomerMetaData fuera de la clase del Cliente y hacerlo público. – Alxandr

+0

No funcionará aunque mueva CustomerMetaData fuera de la clase Cliente y declare como público. Me preocupa que TryValidateObject admita buddyclass (MetadataType)? – ashraf

Respuesta

27

he encontrado la respuesta aquí: http://forums.silverlight.net/forums/p/149264/377212.aspx

MVC reconoce el atributo MetadataType, pero otros proyectos no. Antes de validar, es necesario registrar manualmente la clase de metadatos:

TypeDescriptor.AddProviderTransparent(
      new AssociatedMetadataTypeTypeDescriptionProvider(typeof(Customer), typeof(CustomerMetadata)), typeof(Customer)); 

var isValid = Validator.TryValidateObject(new Customer(), context, results, true); 
+1

Gracias. Si elijo la anotación de datos como mi marco de Validación, entonces Validator.TryValidaeObject debe validar desde cualquier lugar. – ashraf

+0

gracias por una buena respuesta! +1 – Karamafrooz

+0

Ninguna sobrecarga de constructor para la clase AssociatedMetadataTypeTypeDescriptionProvider toma tres argumentos. Veo este problema con el fragmento de código. – RBT

1

Aunque no he probado el código en .NET 4.0, en .NET 3.5/Silverlight 3, su clase de metadatos debería tener este aspecto:

[MetadataType(typeof(Customer.CustomerMetaData))] 
public partial class Customer 
{ 
    internal sealed class CustomerMetaData 
    { 
     private CustomerMetaData() 
     { 
     } 

     [Required(ErrorMessage = "You must supply a name for a customer.")]   
     public string Name; 
    } 
} 
+0

No, todavía no funcionará. Creo que es un error. – ashraf

4

Después de algunas investigaciones que no podía encontrar ningún por lo que TryValidateObject siempre devuelve verdadero si utilizo MetadataType (clase buddy). Pero funciona con el siguiente código (xVal).

public static IEnumerable<ErrorInfo> GetErrors(object instance, string name) 
    { 
     var metadataAttrib = instance.GetType() 
       .GetCustomAttributes(typeof(MetadataTypeAttribute), true) 
       .OfType<MetadataTypeAttribute>().FirstOrDefault(); 
     var buddyClassOrModelClass = metadataAttrib != null 
       ? metadataAttrib.MetadataClassType 
       : instance.GetType(); 
     var buddyClassProperties = TypeDescriptor.GetProperties(buddyClassOrModelClass) 
      .Cast<PropertyDescriptor>(); 
     var modelClassProperties = TypeDescriptor.GetProperties(instance.GetType()) 
      .Cast<PropertyDescriptor>(); 

     var list = from buddyProp in buddyClassProperties 
        join modelProp in modelClassProperties on 
          buddyProp.Name equals modelProp.Name 
        from attribute in buddyProp.Attributes.OfType<ValidationAttribute>() 
        where !attribute.IsValid(modelProp.GetValue(instance)) 
        select new ErrorInfo(
         buddyProp.Name, 
         attribute.FormatErrorMessage(modelProp.Name), 
         instance); 

     if (name != null) 
      list = list.Where(x => x.PropertyName == name); 

     return list; 
    } 
1

Hay un problema por el que el atributo MetadataType no está siendo reconocido por el contexto del objeto. Si bien se puede añadir manualmente el descriptor de tipo antes de la validación: TypeDescriptor.AddProviderTransparent( new AssociatedMetadataTypeTypeDescriptionProvider(typeof(Customer), typeof(CustomerMetaData)), typeof(Customer));

una forma más concisa para manejar sería para actualizar el archivo .tt modelo de entidad, añadir lo siguiente a cada DTO:

Type currentType = MethodBase.GetCurrentMethod().DeclaringType; 
    object[] attributes = currentType.GetCustomAttributes(typeof(MetadataTypeAttribute),false); 
    if(attributes.Length > 0) 
    { 
     //MetadataType attribute found! 
     MetadataTypeAttribute metaDataAttribute = (MetadataTypeAttribute)attributes[0]; 
     TypeDescriptor.AddProviderTransparent(
      new AssociatedMetadataTypeTypeDescriptionProvider(
       currentType, metaDataAttribute.MetadataClassType),currentType); 
    } 

esto le permitirá añadir los atributos de las clases parciales:

[MetadataType(typeof(CustomerMetaData))] 
public partial class Customer 
{ 

} 

public partial class CustomerMetaData 
{ 
    [Required] 
    public string CustomerName { get; set; } 
} 
+0

Hola @Gareth Suarez, creo que esta es una gran idea, ¿puedes proporcionar más información sobre cómo editar el archivo Entity Model.tt? –

+1

De hecho, traté de hacerlo, pero no sé dónde debería incluir su fragmento. Intenté incluirlo en el constructor de cada DTO pero no tuve suerte en absoluto. ¿Alguna idea? Por cierto, estoy tratando de establecer el IgnoreDataMember en algunos de los atributos a través de MetadataType, este método debería funcionar, ¿no? –

Cuestiones relacionadas