9 Stimmen

Bedingte Validierung von Teilen eines ASP.NET MVC-Modells mit DataAnnotations?

Ich habe bestimmte Felder auf meiner Seite, die unter bestimmten Umständen ausgeblendet werden.

Zum Beispiel könnte ich eine "Rechnungsadresse" und eine "Lieferadresse" haben und ich möchte die "Lieferadresse" nicht validieren, wenn das Kontrollkästchen "ShippingSameAsBilling" aktiviert ist.

Ich versuche, die neue Fähigkeiten von DataAnnotations von ASP.NET MVC 2 (Vorschau 1), um dies zu erreichen.

Ich muss die Validierung der "Lieferadresse" verhindern, wenn sie nicht angezeigt wird, und muss einen Weg finden, um dies zu erreichen. Ich spreche vor allem Server-Seite im Gegensatz zu durch Verwendung von Jquery .

Wie kann ich das erreichen? Ich habe mehrere Ideen, im Zusammenhang mit benutzerdefinierten Modellbindung, aber meine derzeit beste Lösung ist unten. Irgendwelche Rückmeldungen zu dieser Methode?

6voto

Simon_Weaver Punkte 129442

Für das CheckoutModel verwende ich diesen Ansatz (die meisten Felder ausgeblendet):

[ModelBinder(typeof(CheckoutModelBinder))]
public class CheckoutModel : ShoppingCartModel
{        
    public Address BillingAddress { get; set; }
    public Address ShippingAddress { get; set; }
    public bool ShipToBillingAddress { get; set; }
}

public class Address
{
    [Required(ErrorMessage = "Email is required")]
    public string Email { get; set; }

    [Required(ErrorMessage = "First name is required")]
    public string FirstName { get; set; }

    [Required()]
    public string LastName { get; set; }

    [Required()]
    public string Address1 { get; set; }
}

Der benutzerdefinierte Modellbinder entfernt alle ModelState-Fehler für Felder, die mit "ShippingAddress" beginnen, wenn er welche findet. Dann gibt 'TryUpdateModel()' true zurück.

    public class CheckoutModelBinder : DefaultModelBinder
    {
        protected override void OnModelUpdated(ControllerContext controllerContext,
                                               ModelBindingContext bindingContext) {

            base.OnModelUpdated(controllerContext, bindingContext);

            var model = (CheckoutModel)bindingContext.Model;

            // if user specified Shipping and Billing are the same then 
            // remove all ModelState errors for ShippingAddress
            if (model.ShipToBillingAddress)
            {
                var keys = bindingContext.ModelState.Where(x => x.Key.StartsWith("ShippingAddress")).Select(x => x.Key).ToList();
                foreach (var key in keys)
                {
                    bindingContext.ModelState.Remove(key);
                }
            }
        }    
    }

Gibt es bessere Lösungen?

3voto

andrewbadera Punkte 1362

2voto

Matt Kocaj Punkte 10936

Ich kann Ihr Dilemma verstehen. Ich bin auf der Suche nach anderen Validierungslösungen, auch im Hinblick auf komplexe Validierungsregeln, die für mehr als eine Eigenschaft eines bestimmten Modellobjekts oder sogar für viele Eigenschaften von verschiedenen Modellobjekten in einem Objektgraphen gelten könnten (wenn Sie das Pech haben, verknüpfte Objekte wie diese zu validieren).

Die Begrenzung der IDataErrorInfo Schnittstelle ist, dass ein Modellobjekt den gültigen Zustand einfach dann erfüllt, wenn keine der Eigenschaften Fehler aufweist. Dies bedeutet, dass ein gültig Objekt ist eines, bei dem alle seine Eigenschaften auch gültig . Allerdings kann ich eine Situation haben, wo, wenn Eigenschaft A, B und C gültig sind - dann das gesamte Objekt gültig ist. sondern auch wenn Eigenschaft A nicht gültig ist, aber B y C sind, dann erfüllt das Objekt die Gültigkeit. Ich habe einfach keine Möglichkeit, diese Bedingung/Regel mit dem IDataErrorInfo Schnittstelle / DataAnnotations Attribute.

So fand ich dies Delegiertenansatz . Viele der hilfreichen Weiterentwicklungen in MVC gab es zum Zeitpunkt der Erstellung dieses Artikels noch nicht, aber das Kernkonzept sollte Ihnen helfen. Anstatt Attribute zu verwenden, um die Validierungsbedingungen eines Objekts zu definieren, erstellen wir delegierte Funktionen, die komplexere Anforderungen validieren, und da sie delegiert sind, können wir sie wiederverwenden. Sicherlich ist es mehr Arbeit, aber die Verwendung von Delegaten bedeutet, dass wir in der Lage sein sollten, den Validierungsregelcode einmal zu schreiben y alle Validierungsregeln an einem Ort zu speichern (vielleicht in der Dienstschicht) y (das coole Teil) verwenden sogar die MVC 2 DefaultModelBinder um die Validierung automatisch aufzurufen (ohne haufenweise Überprüfungen in unseren Controller-Aktionen - wie in Scotts Blog beschrieben, können wir das mit DataAnnotations . Siehe dazu die letzter Absatz vor der Überschrift 'Strongly Typed UI Helpers')!

Ich bin sicher, Sie können den im obigen Artikel vorgeschlagenen Ansatz mit anonymen Delegierten wie Func<T> o Predicate<T> und das Schreiben von benutzerdefinierten Codeblöcken für die Validierungsregeln ermöglicht eigenschaftsübergreifende Bedingungen (z. B. die von Ihnen erwähnte Bedingung, wenn Ihre ShippingSameAsBilling Eigenschaft wahr ist, können Sie weitere Regeln für die Lieferadresse usw. ignorieren.)

DataAnnotations dient dazu, einfache Validierungsregeln für Objekte aufzustellen wirklich einfach mit sehr wenig Code. Wenn sich Ihre Anforderungen weiterentwickeln, werden Sie jedoch komplexere Regeln validieren müssen. Die neuen virtuellen Methoden im MVC2-Modellbinder sollten uns weiterhin Möglichkeiten bieten, unsere zukünftigen Validierungserfindungen in das MVC-Framework zu integrieren.

2voto

Haacked Punkte 56079

Stellen Sie sicher, dass die Felder, die nicht überprüft werden sollen, nicht in die Aktion aufgenommen werden. Wir überprüfen nur die Felder, die tatsächlich gebucht wurden.

Bearbeiten: (vom Fragesteller)

Dieses Verhalten hat sich in MVC2 RC2 geändert:

Standard-Validierungssystem validiert gesamte Modell Die Standardvalidierung System in ASP.NET MVC 1.0 und in Previews von ASP.NET MVC 2 vor RC 2 prüfte nur Modelleigenschaften, die an den Server gesendet wurden. In ASP.NET MVC 2 ist das neue Verhalten, dass alle Modelleigenschaften validiert werden, wenn das Modell validiert wird, unabhängig davon ob ein neuer Wert gepostet wurde. Anwendungen, die von dem ASP.NET MVC 1.0 abhängen, müssen möglicherweise Änderungen. Für weitere Informationen über diese Änderung finden Sie unter dem Eintrag Eingabe Validierung vs. Modellvalidierung in ASP.NET MVC im Blog von Brad Wilson.

1voto

Todd Smith Punkte 16604

Für die komplexeren Fälle bin ich von den einfachen DataAnnotations zu den folgenden übergegangen: Validierung mit Besuchern und Erweiterungsmethoden .

Wenn Sie Ihre DataAnnotations verwenden möchten, würden Sie etwas wie das Folgende ersetzen:

public IEnumerable<ErrorInfo> BrokenRules (Payment payment)
{   
    // snip... 
    if (string.IsNullOrEmpty (payment.CCName))
    {
      yield return new ErrorInfo ("CCName", "Credit card name is required");
    }
}

mit einer Methode zur Validierung einer Eigenschaft nach Name über DataAnnotations (die ich atm nicht haben).

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X