9

DataAnnotations funktioniert nicht mit Buddy-Klasse. Der folgende Code validiert immer true. Warum ?Validierung funktioniert nicht, wenn ich Validator.TryValidateObject verwenden

var isValid = Validator.TryValidateObject (neuer Kunde(), Kontext, Ergebnisse, wahr);

und hier ist die Buddy-Klasse.

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

Hier ist ein weiterer Thread mit derselben Frage., Aber keine Antwort. link text

+0

Ich bin mir nicht sicher, aber ich denke, Sie sollten die Klassen nicht verschachteln. Ich denke auch, dass die CustomMetaData-Klasse ohne das public-Schlüsselwort nicht zugänglich wäre. Versuchen Sie, CustomerMetaData aus der Customer-Klasse zu entfernen und öffentlich zu machen. – Alxandr

+0

Es funktioniert nicht, selbst wenn ich CustomerMetaData aus der Customer-Klasse verschiebe und als public deklariere. Ich habe Sorge, dass TryValidateObject Buddyclass (MetadataType) unterstützt? – ashraf

Antwort

27

fand ich die Antwort hier: http://forums.silverlight.net/forums/p/149264/377212.aspx

MVC erkennt das MetadataType Attribut, aber auch andere Projekte nicht. Bevor die Validierung, müssen Sie manuell die Metadatenklasse registrieren:

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

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

Danke. Wenn ich die Datenannotation als Validierungsframework auswähle, sollte Validator.TryValidaeObject von überall validieren. – ashraf

+0

danke für die nette antwort! +1 – Karamafrooz

+0

Keine Konstruktorüberladung für die AssociatedMetadataTypeTypeDescriptionProvider-Klasse benötigt drei Argumente. Ich sehe dieses Problem mit dem Code-Snippet. – RBT

1

Obwohl ich nicht Ihren Code testen in .NET 4.0, in .NET 3.5/Silverlight 3, Ihre Metadatenklasse sollte wie folgt aussehen:

[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

Nein, es wird immer noch nicht funktionieren. Ich denke, es ist ein Fehler. – ashraf

4

Nach einigen Recherchen konnte ich nicht finden Grund, warum TryValidateObject immer true zurückgibt, wenn ich MetadataType (Buddy-Klasse) verwende. Aber es funktioniert mit dem folgenden Code (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

Es gibt ein Problem, bei dem das MetadataType Attribut wird vom Objektkontext nicht erkannt zu werden. Während Sie manuell den Typdeskriptor vor der Validierung hinzufügen:

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

: TypeDescriptor.AddProviderTransparent( new AssociatedMetadataTypeTypeDescriptionProvider(typeof(Customer), typeof(CustomerMetaData)), typeof(Customer));

eine prägnante Weise zu handhaben würde es die Entity Model .tt Datei zu aktualisieren sein, den folgenden zu jedem DTO hinzufügen Dadurch können Sie die Attribute zu den partiellen Klassen hinzufügen:

+0

Hallo @Gareth Suarez, ich denke, das ist eine großartige Idee, können Sie weitere Informationen zum Bearbeiten der Datei Entity Model.tt bereitstellen? –

+1

Ich habe es tatsächlich versucht, aber ich weiß nicht, wo ich dein Snippet einfügen soll. Ich habe versucht, es in den Konstruktor jedes DTO aufzunehmen, aber ich hatte überhaupt kein Glück. Irgendeine Idee? BTW, ich versuche, den IgnoreDataMember in einigen der Attribute über MetadataType zu setzen, sollte diese Methode funktionieren, oder? –

Verwandte Themen