2013-06-17 7 views
6

einfache Daten Anmerkungen auf Eigenschaften Putting ist groß,Anwenden von Datenanmerkungen auf Untereigenschaften des Ansichtsmodells in MVC?

public class UnicornViewModel 
{ 
    [Required] 
    public string Name { get; set; } 

Aber läßt sagen, ich bin so etwas wie dieses:

public class SuperPower 
{ 
    public class Name { get; set; } 
} 

public class UnicornViewModel 
{ 
    [Required] 
    public string Name { get; set; } 

    public SuperPower PrimarySuperPower { get; set; } 

    public SuperPower SecondarySuperPower { get; set; } 

Wie bewerbe ich mich das gewünschte Attribut auf PrimarySuperPower.Name während es verlassen optional für SecondarySuperPower.Name? Vorzugsweise 1. etwas, das mit der Validierung auf der Client-Seite verknüpft ist und 2. ohne besondere Handhabung wie das Überprüfen des Werts von PrimarySuperPower.Name im Action/Custom-Validator und das Hinzufügen eines ModelState-Fehlers, wenn dieser leer ist. Es wäre toll, wenn es so etwas wie war:

[Required(p => p.Name)] 
    public SuperPower PrimarySuperPower { get; set; } 

    public SuperPower SecondarySuperPower { get; set; } 
+0

Woher weiß das Attribut, woran es angehängt ist? Attribute sind nur Metadaten. – Romoku

Antwort

1

Im Allgemeinen wird diese nicht unterstützt wird: ASP.NET MVC3 Validation of nested view model object fields

Aber Sie können benutzerdefinierte Modellvalidierung implementieren, aber so für Client- und Server-Seite tun wird ziemlich kompliziert.

Wenn Sie eine eigene Vorlage für das Superpower-Objekt haben, könnte es für ein Attribut der eigenen Herstellung aussehen:

[RequiredSubProperty("Name")] 
    public SuperPower PrimarySuperPower { get; set; } 

Und in der Vorlage gleich hinter der unauffälligen Validierungsattribute in die Htmlattributes Parameter des TextBoxFor oder welchen Eingabehilfen Sie auch verwenden.

Wenn Sie keine Vorlage verwenden, würde ich all dies verzichten und die unauffälligen Validierungsattribute nur dann in den htmlAttributes-Parameter übergeben, wenn der Vorname, aber nicht der zweite angezeigt wird.

Eine weitere Option ist für die UnicornViewModel wie

public class UnicornViewModel 
{ 
    [Required] 
    public string Name { get; set; } 

    [Required] 
    public string PrimarySuperPowerName { get; set; } 

    public string SecondarySuperPowerName { get; set; } 

abgeflacht werden Es hängt alles davon ab, wie viel Wiederverwendung Sie kompliziertere Ansätze bekommen könnten. Als ich versuchte, Templating viel zu verwenden, fand ich, dass in bestimmten Kontexten bestimmte Dinge über Templates keinen Sinn ergaben, und so würde ich eine Menge Variationen an einer Objektvorlage benötigen (wenn eine Kindvorlage auf der Seite eines Elternteils angezeigt wird) Für das Kind ist es nicht sinnvoll, eine URL zu haben, die mit dem Detail des Elternteils verknüpft ist, da Sie sich bereits auf dieser Seite befinden, aber überall wo die Kindvorlage verwendet wird, sollte diese Verknüpfung zum übergeordneten Element angezeigt werden. Letztlich habe ich aufgehört, Vorlagen zu verwenden, und verwende gelegentlich Teiltöne, wo es einen guten Fall für viel Wiederverwendung gibt. Auf der Benutzeroberfläche entspricht der Gummi der Straße und ViewModels werden nicht so gut strukturiert sein wie Ihre Entity/Business-Modelle.

0

Dies ist mit den Standarddatenattributen nicht möglich. Die von Ihnen erwähnte erforderliche Syntax wäre auch in einer benutzerdefinierten Implementierung nicht möglich, da es keinen Verweis auf das Objekt gibt, für das Sie das Lambda verwenden möchten.

Sie können besser mit einer Drittanbieter-Validierungsbibliothek wie FluentValidation arbeiten. Es bietet eine hohe Flexibilität für Ihre Validierungsanforderungen.

0

Ich persönlich bin ein Fan der ModelMetadataClass, um meine ViewModels zu leiten. Wenn Sie bereit sind, auf Schritt gehen extra und nutzen AutoMapper könnten Sie ein Ansichtsmodell wie folgt zu erstellen:

public class SuperPower 
{ 
    public string Name { get; set; } 
} 

[MetadataType(typeof(UnicornViewModel.UnicornViewModelMetaData))] 
public class UnicornViewModel 
{ 
    public string Name { get; set; } 

    public RequiredSuperPowerViewModel PrimarySuperPower { get; set; } 

    public SuperPower SecondarySuperPower { get; set; } 

    public class UnicornViewModelMetaData 
    { 
     [Required] 
     public string Name { get; set; } 

    } 
} 

[MetadataType(typeof(UnicornViewModel.UnicornViewModelMetaData))] 
public class RequiredSuperPowerViewModel : SuperPower 
{ 
    public class RequiredSuperPowerModelMetaData 
    { 
     [Required] 
     public string Name { get; set; } 

    } 
} 

Dies ermöglicht es Ihnen zu wählen, welche Felder für eine bestimmte Modellklasse erforderlich möchten, ohne Ihr Modell zu beeinträchtigen.

Wenn Sie AutoMapper verwenden Sie die Original-Superpower rehydratisieren lassen sich wie folgt:

sein
SuperPower reqSuperPower = AutoMapper.Mapper.Map<RequiredSuperPowerViewModel, SuperPower>(Data.PrimarySuperPower); 
0

Dies könnte eine späte Antwort, aber ich diese Frage gefunden, wenn für die gleiche Sache zu suchen. Dies ist, wie ich meine besondere Situation gelöst:

Bevor ich dies hatte:

public class ProductVm 
{ 
    //+ some other properties   

    public Category Category {get; set;} 
    public Category ParentCategory {get; set;} 
} 

Für welche ich etwas in etwas wie haben wollte:

public class ProductVm 
{ 
    //some other properties   

    [DisplayName("Product Category", e => e.Description)] 
    public Category Category {get; set;} 
    [DisplayName("Parent Category", e => e.Description)] 
    public Category ParentCategory {get; set;} 
} 

Ich konnte nicht betreten dies im Modell selbst, da beide die gleiche Objektklasse sind.

ich es so gelöst (da ich nur die Beschreibung Wert in diesem Fall zu lesen, benötigt und schreiben Sie es nicht):

public class ProductVm 
{ 
    //some other properties   

    public Category Category {get; set;} 
    public Category ParentCategory {get; set;} 

    [DisplayName("Product Category")] 
    public string Category => Category.Description; 

    [DisplayName("Main Category")] 
    public string ParentCategory => ParentCategory.Description; 
} 

Sie könnten es möglich nur umschreiben ein bisschen mehr die verbleibenden privaten Träger zu halten Felder und entfernen Sie die Kapselung der Eigenschaft der Kategorie-Objekte, aber in meinem Fall brauchte ich sie noch für andere Zwecke öffentlich zu sein.

In Bezug auf die obige Frage ich folgendes tun würde:

public class UnicornViewModel 
{ 
    [Required] 
    public string Name { get; set; } 

    public SuperPower PrimarySuperPower { get; set; } 

    public SuperPower SecondarySuperPower { get; set; } 

    [Required] 
    public string PrimarySuperPowerName 
    { 
     get { return PrimarySuperPower.Name; } 
     set { PrimarySuperPower.Name = value; } 
    } 

    public string SecondarySuperPowerName 
    { 
     get { return SecondarySuperPower.Name; } 
     set { SecondarySuperPower.Name = value; } 
    } 
} 

Und dann würde ich meinen Blick auf die String-Eigenschaften binden und die Supermacht Eigenschaften auszuschließen.

Verwandte Themen