2009-10-13 3 views
27

Ich verwende die Datenanmerkungs-Validierung ausgiebig in ASP.NET MVC 2. Diese neue Funktion hat mir viel Zeit gespart, da ich jetzt sowohl die clientseitige Validierung als auch die serverseitige Validierung an einer Stelle definieren kann. Während ich einige detaillierte Tests durchführte, erkannte ich jedoch, dass es für jemanden ziemlich einfach ist, die serverseitige Validierung zu umgehen, wenn ich mich nur auf die Datenanmerkung verlassen würde. Wenn ich beispielsweise ein erforderliches Feld durch Kommentieren der Eigenschaft mit dem Attribut [Erforderlich] definiert und ein Textfeld für dieses erforderliche Feld in einem Formular platziert hat, kann ein Benutzer das Textfeld einfach aus dem DOM entfernen (was einfach über Firebug möglich ist). und jetzt wird die Datenanmerkungsüberprüfung für diese Eigenschaft während ModelBinding innerhalb eines Controllers nicht ausgelöst. Um sicherzustellen, dass die "erforderliche" Validierung ausgelöst wird, kann ich die Validierung wiederholen, nachdem ModelBinding passiert ist, aber dann würde ich meine Validierungslogik wiederholen.ASP.NET MVC: Ist die Validierung der Datenannotation ausreichend?

Was ist die Empfehlung von allen zur Validierung? Ist die Validierung der Datenanmerkung ausreichend? Oder muss die Validierung wiederholt werden, um sicherzustellen, dass Validierungen in allen Situationen ausgelöst werden?

Follow-up-Kommentar: Basierend auf den Antworten unten, so scheint es, dass ich nicht allein auf der Modell Binder und Daten Annotation Validierung verlassen kann. Da wir zu dem Schluss kommen, dass eine zusätzliche serverseitige Validierung erforderlich ist, gibt es eine einfache Möglichkeit für meine Serviceebene, eine Validierung basierend auf den in den Datenannotationen definierten Daten auszulösen. Es scheint, dass dies uns das Beste aus beiden Wörtern bringt ... wir werden den Validierungscode nicht wiederholen müssen, aber wir werden trotzdem sicherstellen, dass die Validierung ausgeführt wird, selbst wenn Model Binder sie nicht auslöst.

Ich werde diese Follow-up-Kommentar als eine separate Frage, da es eine andere Frage stellt als die ursprüngliche Frage.

+0

Koritnik Antwort beantwortet Ihre Follow-up-Abfrage. Ich mache meine Validierung ähnlich wie die Antwort, die er gepostet hat. Dieselbe DataAnnotation-Definition kann sowohl für die Server- als auch für die Client-Validierung verwendet werden. –

+1

Die Validierung der Datenanmerkung ist in Ordnung, wenn die bereitgestellten Validierungsattribute und das Framework für Sie geeignet sind. Das Verhalten mit Erforderlich wurde für ASP.NET MVC 2 RTM aufgrund von Community-Feedback geändert, sodass [Erforderlich] nun wie erwartet funktioniert. Optisch, überprüfen Sie: Validierungsblock (Enterprise Library), xVal, NHibernate Validatoren (angeblich keine Abhängigkeit von NHibernate ORM). – miha

+0

'" Ich werde diesen Follow-up-Kommentar als separate Frage veröffentlichen, da sie eine andere Frage stellt als die ursprüngliche Frage. "' Ein Link dazu wäre keine schlechte Idee, oder? – Sinjai

Antwort

18

Ich denke, wachsam in Bezug auf die Sicherheit, die Sie wählen sollten Ihnen die Servervalidierung als Priorität zu geben und sicherzustellen, dass dies immer Ihr Fallback ist. Ihre Server-Validierung sollte ohne die Client-Validierung funktionieren. Client-Validierung ist mehr für UX und das ist für Ihr Design von größter Bedeutung, es ist sekundär zur Sicherheit. In diesem Sinne wiederholen Sie Ihre Validierung. Ein Ziel besteht häufig darin, Ihre App so zu entwickeln, dass die Server- und Clientvalidierung so weit wie möglich integriert werden kann, um den Aufwand für die Validierung auf dem Server und dem Client zu reduzieren. Aber seien Sie versichert, dass Sie beides tun müssen.

Wenn das Umgehen der Client-Validierung (mittels DOM-Manipulation) die Servervalidierung vermeidet (was anscheinend darauf hinweist), wird die Servervalidierung für diese Instanz möglicherweise nicht ordnungsgemäß angewendet. Sie sollten die Servervalidierung in Ihrer Controller-Aktion oder in einer Service-Schicht erneut aufrufen. Das von Ihnen beschriebene Szenario sollte die Servervalidierung nicht vereiteln.

Mit dem Szenario, das Sie beschreiben, Attribute die DataAnnotation Methode ausreichend sein sollte. Es scheint, dass Sie einfach ein paar Änderungen am Code vornehmen müssen, um sicherzustellen, dass die Server-Validierung auch aufgerufen wird, wenn das Formular absenden.

2

Die DataAnnotation ist sicherlich nicht genug. Ich benutze es auch umfassend, um meine Aufrufe an das Domänenmodell vorab zu validieren, um eine bessere Fehlerberichterstattung zu erhalten und so früh wie möglich zu versagen.

Sie können das DataAnnotation-Modell jedoch selbst anpassen, um sicherzustellen, dass Eigenschaften mit [Erforderlich] veröffentlicht werden müssen. (wird später mit Code nachkommen).

UPDATE Erhalten Sie die Quelle für DataAnnotations Modell Binder und diese Linie in DataAnnotationsModelBinder.cs finden

// Only bind properties that are part of the request 
if (bindingContext.ValueProvider.DoesAnyKeyHavePrefix(fullPropertyKey)) { 

ändern es zu

// Only bind properties that are part of the request 
bool contextHasKey = bindingContext.ValueProvider.DoesAnyKeyHavePrefix(fullPropertyKey); 
bool isRequired = GetValidationAttributes(propertyDescriptor).OfType<RequiredAttribute>().Count() > 0; 
if (contextHasKey || (!contextHasKey && isRequired)) { 
+0

Danke Martijn. Ich freue mich darauf, Ihren Code zu sehen. –

+0

Sicher, ich postete dies vor dem Verlassen zur Arbeit (bei der Arbeit noch jetzt) ​​so keine Zeit zu programmieren :(. Ich änderte die Bindemittel vor etwas, da es verschachtelte Objekte nicht überprüft und ungültige Eigenschaften auf Null zurückgesetzt, die ich nicht einverstanden war http://StackOverflow.com/Questions/820468/how-does-dataannotationsmodelbinder-work-with-custom-viewmodels/864541#864541 Ich habe die erforderlichen Prüfungen seit damals auch hinzugefügt, aber möchte sie ausprobieren, wenn ich nach Hause komme –

+0

Aktualisiert mit Code, aber ich bin nicht in der Lage, es richtig zu testen, werde es morgen wieder tun, aber es geschrieben, vielleicht können Sie es schneller bewerten.Es besteht die Unit-Tests des Projekts, aber um fair zu sein ist kein Test, der diesen Fall testet: D. –

7

I gepaart xVal mit DataAnnotations und habe meinen eigenen Action-Filter geschrieben, die zu Validierungszwecken alle Entitätstyp Parameter überprüft. Wenn also ein Feld im Postback fehlt, füllt dieser Validator das ModelState-Dictionary, weshalb das Modell ungültig ist.

Voraussetzungen:

  • mein Unternehmen/Modell alle IObjectValidator Schnittstelle implementieren Objekte, die Validate() Methode deklariert.

    public void OnActionExecuting(ActionExecutingContext filterContext) 
    { 
        IEnumerable<KeyValuePair<string, object>> parameters = filterContext.ActionParameters.Where<KeyValuePair<string, object>>(p => p.Value.GetType().Equals(this.ObjectType ?? p.Value.GetType()) && p.Value is IObjectValidator); 
        foreach (KeyValuePair<string, object> param in parameters) 
        { 
         object value; 
         if ((value = param.Value) != null) 
         { 
          IEnumerable<ErrorInfo> errors = ((IObjectValidator)value).Validate(); 
          if (errors.Any()) 
          { 
           new RulesException(errors).AddModelStateErrors(filterContext.Controller.ViewData.ModelState, param.Key); 
          } 
         } 
        } 
    } 
    

    Meine Controller-Aktion wird wie folgt definiert dann:

  • meine Attributklasse ist ValidateBusinessObjectAttribute
  • xVal Validierung Bibliothek

Aktion Filtercode genannt

[ValidateBusinessObject] 
public ActionResult Register(User user, Company company, RegistrationData registrationData) 
{ 
    if (!this.ModelState.IsValid) 
    { 
     return View(); 
    } 
    ... 
} 
+0

haben Sie ein detaillierteres Beispiel, wie Sie dieses oder ein herunterladbares Projekt verwenden können, vielleicht –

+0

@geocine: Wo scheint das Problem zu sein? Benutzt du MVC1? Neuere Versionen benötigen dies nicht, da sie starke Typparameter automatisch validieren ... Aber dieses Beispiel ist hier genauso detailliert, wie es in der Realität sein sollte. Also wo scheint das Problem zu sein? –

+0

Ich bin gerade vorbeigekommen und ich bin neu in Aspmvc lesen über Validierungsprobleme. Ich habe vergessen, dass ich MVC 2 benutze. –

2

Ich schrieb mein eigener ValidationService für MVC 1.0 durch Kopieren von Mustern aus beiden xV ALs DataAnnotationsRuleProvider und Microsofts DataAnnotationsModelBinder (und Kommentare von Martijn). Die Serviceschnittstelle ist unten:

public interface IValidationService 
{ 
    void Validate(object instance); 

    IEnumerable<ErrorInfo> GetErrors(object instance); 
} 

public abstract class BaseValidationService : IValidationService 
{ 
    public void Validate(object instance) 
    { 
     var errors = GetErrors(instance); 

     if (errors.Any()) 
      throw new RulesException(errors); 
    } 

    public abstract IEnumerable<ErrorInfo> GetErrors(object instance); 
} 

Der Dienst ist ein Validierungs Kufe, die die Eigenschaft Baum der Objektinstanz geht sie empfängt, und führt tatsächlich die Validierungsattribute, dass es auf jeder Eigenschaft findet, den Aufbau eine Liste von Errorinfo-Objekten, wenn Attribute sind nicht gültig. (Ich poste die gesamte Quelle, aber es wurde für einen Client geschrieben und ich weiß noch nicht, ob ich dazu berechtigt bin.)

Sie können dann Ihre Controller haben, Business Logic Services explizit Validierung aufrufen, wenn Sie sind bereit, anstatt sich ausschließlich auf den Modellbinder zur Validierung zu verlassen.

Es gibt ein paar andere Gefahren, die Sie sollten sich bewusst sein:

  • Die Standard-Datatype in Daten Anmerkungen tatsächlich jede Datentyp Validierung nicht tun, so dass Sie benötigen zu schreiben ein neues Attribut, dass tatsächlich xVal regelmäßige Ausdrücke (oder etwas anderes) zu ausführen serverseitige Datentyp Validierung verwendet.
  • xVal ist zu Fuß nicht Eigenschaften clientseitige Validierung zu erstellen, so mögen Sie vielleicht einige Änderungen dort zu erhalten robuste clientseitige Validierung machen.

Wenn ich erlaubt bin und Zeit habe, werde ich versuchen, mehr Quelle zur Verfügung zu stellen ...

1

Siehe Codeproject Server-side Input Validation using Data Annotations

Input-Validierung kann automatisch auf der Client-Seite in ASP.NET MVC oder explizit das Modell gegen die Regeln der Validierung durchgeführt werden. Dieser Tipp wird beschreiben, wie es manuell auf der Server-Seite einer ASP.NET-Anwendungen oder innerhalb des Repository-Code von WPF Anwendungen durchgeführt werden kann.

 // Use the ValidationContext to validate the Product model against the product data annotations 
     // before saving it to the database 
     var validationContext = new ValidationContext(productViewModel, serviceProvider: null, items:null); 
     var validationResults = new List<ValidationResult>(); 

     var isValid = Validator.TryValidateObject(productViewModel, validationContext,validationResults, true);