26

Wenn ich ein Suchobjekt mit einer Liste von Feldern habe, kann ich mithilfe des Namespaces System.ComponentModel.DataAnnotations festlegen, dass mindestens eines der Felder in der Suche nicht null oder leer ist? d. h. alle Felder sind optional, aber mindestens eines sollte immer eingegeben werden.Daten Anmerkungen zur Validierung, mindestens ein Pflichtfeld?

Antwort

18

ich einen benutzerdefinierten Validator für diese schaffen würde - es gewann Geben Sie keine Client-Seite Validierung, nur Server-Seite.

Beachten Sie, dass für diese arbeiten, werden Sie nullable Typen werden müssen verwenden, als Werttypen zu 0 oder false ausfällt:

Erste einen neuen Prüfers erstellen:

using System.ComponentModel.DataAnnotations; 
using System.Reflection; 

// This is a class-level attribute, doesn't make sense at the property level 
[AttributeUsage(AttributeTargets.Class)] 
public class AtLeastOnePropertyAttribute : ValidationAttribute 
{ 
    // Have to override IsValid 
    public override bool IsValid(object value) 
    { 
    // Need to use reflection to get properties of "value"... 
    var typeInfo = value.GetType(); 

    var propertyInfo = typeInfo.GetProperties(); 

    foreach (var property in propertyInfo) 
    { 
     if (null != property.GetValue(value, null)) 
     { 
     // We've found a property with a value 
     return true; 
     } 
    } 

    // All properties were null. 
    return false; 
    } 
} 

Sie können dann Ihre Modelle mit diesem dekorieren:

[AtLeastOneProperty(ErrorMessage="You must supply at least one value")] 
public class SimpleTest 
{ 
    public string StringProp { get; set; } 
    public int? Id { get; set; } 
    public bool? BoolProp { get; set; } 
} 

dann, wenn Sie ModelState.IsValid Ihre Validator nennen b e angerufen, und Ihre Nachricht wird der ValidationSummary Ihrer Ansicht hinzugefügt. Beachten Sie, dass Sie dies erweitern können, um nach dem Typ der zurückkommenden Eigenschaft zu suchen, oder nach Attributen zu suchen, die die Validierung einschließen/ausschließen, wenn Sie dies möchten - dies setzt einen generischen Validator voraus, von dem nichts bekannt ist der Typ, der validiert wird.

+0

+1 Nizza. Ich wusste nicht, dass das Hinzufügen von Attributen auf Klassenebene mit DataAnnotations möglich ist. – Steven

+0

Das sieht wirklich gut aus, ich werde vor dem Ende der Woche darauf zurückkommen und deine Antwort geben. Ich werde dich wissen lassen, wie es sich entwickelt! Danke – Boob

+1

@Boob Sie Lügner. – JefClaes

0

Wenn Sie komplexe Validierung gegen jede .NET-Klasse tun wollen, ohne sie mit Anmerkungen Litering, Blick auf FluentValidation oder für .Net 2.0, FluentValidation for 2.0

+1

Daniel, danke für die Antwort, aber als wir die Anmerkungen erfolgreich bisher im Projekt verwendet haben, und es ist sehr gut für das, was wir gebraucht haben, möchte ich versuchen, Bleibe bei dieser Validierungsmethode. Das ist der erste wirkliche Stolperstein bis jetzt und ich hoffe, dass jemand eine nette Lösung für mich haben kann! :) – Boob

+0

Keine Sorgen. Wenn Sie Zeit haben, schauen Sie sich die Links an. Sie finden den Fluent-Ansatz intuitiv und einfach zu bedienen. Und sehr mächtig. –

+0

Will, danke nochmal – Boob

13

Ich habe Zhaph Antwort erweitert, um die Gruppierung von Eigenschaften zu unterstützen.

[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] 
public class AtLeastOnePropertyAttribute : ValidationAttribute 
{ 
    private string[] PropertyList { get; set; } 

    public AtLeastOnePropertyAttribute(params string[] propertyList) 
    { 
     this.PropertyList = propertyList; 
    } 

    //See http://stackoverflow.com/a/1365669 
    public override object TypeId 
    { 
     get 
     { 
      return this; 
     } 
    } 

    public override bool IsValid(object value) 
    { 
     PropertyInfo propertyInfo; 
     foreach (string propertyName in PropertyList) 
     { 
      propertyInfo = value.GetType().GetProperty(propertyName); 

      if (propertyInfo != null && propertyInfo.GetValue(value, null) != null) 
      { 
       return true; 
      } 
     } 

     return false; 
    } 
} 

Verbrauch:

[AtLeastOneProperty("StringProp", "Id", "BoolProp", ErrorMessage="You must supply at least one value")] 
public class SimpleTest 
{ 
    public string StringProp { get; set; } 
    public int? Id { get; set; } 
    public bool? BoolProp { get; set; } 
} 

Und wenn Sie zwei Gruppen haben wollen (oder mehr):

[AtLeastOneProperty("StringProp", "Id", ErrorMessage="You must supply at least one value")] 
[AtLeastOneProperty("BoolProp", "BoolPropNew", ErrorMessage="You must supply at least one value")] 
public class SimpleTest 
{ 
    public string StringProp { get; set; } 
    public int? Id { get; set; } 
    public bool? BoolProp { get; set; } 
    public bool? BoolPropNew { get; set; } 
} 
+2

Das ist großartig - danke. Es ist erwähnenswert, dass eine Validierung auf Klassenebene wie diese nur ausgelöst wird (d. H. Wenn IsValid() aufgerufen wird), wenn alle Validierungen auf Eigenschaftsebene erfolgreich bestanden werden. – VictorySaber

+0

Großartiger Code, funktioniert sehr gut. Vielen Dank ! – Jacob

1

Diese Frage ist ziemlich alt, aber wie von .NET 3.5 (I glauben), IValidatableObject kann mit schwierigen Validierungssituationen helfen. Sie können es implementieren, um beliebige Geschäftsregeln zu validieren. In diesem Fall, so etwas wie:

public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) 
{ 
    if (string.IsNullOrWhiteSpace(FieldOne) && string.IsNullOrWhiteSpace(FieldTwo)) 
     yield return new ValidationResult("Must provide value for either FieldOne or FieldTwo.", new string[] { "FieldOne", "FieldTwo" }); 
} 
Verwandte Themen