Remote Validation in MVC 3

18 Mai 2013
Jelena Barth


Remote Validation ist eines der neuen Features des ASP.NET MVC 3 Frameworks. Diese Technik erlaubt es dem Entwickler eine clientseitige Validierung anzuwenden, die eine Aktionsmethode aufruft, die auf dem Server agiert. Einfacher gesagt, es ist ein Ajax-Aufruf, der Benutzereingaben serverseitig auswertet.

Angenommen, Sie haben ein Eingabefeld und der eingegebene Wert, welcher in die Datenbank geschrieben wird soll eindeutig sein. Ein klassisches Beispiel dafür: Beim Registrieren eines neuen Benutzers soll überprüft werden ob der eingegebene Name verfügbar ist. Bei einem Formular und serverseitiger Validierung wird erst das gesamte Formular an den Server gepostet, wo dann die Validierung stattfindet.

Bei der Remote Validation werden nur die mit [Remote] markierten Attribute zum Server geschickt und ausgewertet. Dadurch ist die Anfrage an den Server relativ schlank, was sich auch auf die Seiten-Performance positiv auswirkt.

Wie funktioniert es?

Die Klasse RemoteAttribute benutzt die Funktionalität des jQuery Validation Plugins, welches eine Menge der clientseitigen Validierungsmethoden enthält.

Mithilfe der jQuery Validation Skripte wird die serverseitige Validierung angestoßen, die aber wie clientseitige Validierung aussieht. Das bedeutet: Kein POST des gesamten Formulars für die Validierung eines einzigen Eingabefeldes, der Benutzer muss nicht ggf. erst das ganze Formular ausfüllen, und zumindest für die Remote Validation muss man keine einzige Zeile JavaScript Code schreiben!

Es ist eine „faule“ Validierung - die von Ihnen implementierte Validierungs-methode wird von der jQuery aufgerufen sobald das Feld den Fokus verliert. So wird der Benutzer nicht ständig mit Fehlermeldungen während seiner Eingabe genervt. Allerdings, nach dem ersten „Fehlverhalten“ des Benutzers wird die Validierung sehr „fleißig“ – jeder Tastendruck wird überprüft (das liegt an dem jQuery Validation Plug-in).

Wie soll man es anwenden und worauf soll man achten?

  • Im Projekt müssen ClientValidation und UnobtrusiveJavaScript Modi aktiviert/an sein.
  • Nicht vergessen die entsprechenden Bibliotheken von jQuery einzubinden: Validate und Validate.Unobtrusive.
  • Validierungsmethode schreiben. Diese muss ein JsonResult zurückgeben.
  • Die Validierungsmethode kann in dem gleichen Controller implementiert werden, der für die View zuständig ist. Oder Sie entscheiden sich für eine saubere Trennung, in dem Sie einen Validierungscontroller erstellen. Ein schönes Beispiel dazu zum Herunterladen gibt es auf der MSDN Seite.
  • Remote Validation zum gewünschten Attribut des Models hinzufügen. [Remote("ActionName", "ControllerName")], wobei "ControllerName" der Name des Controllers ist, in dem sich die Validierungsmethode "ActionName" befindet.

ACHTUNG! Sie müssen nur ein paar Regeln beachten, damit der MVC 3 Framework „Zauber“ wirkt:

  • Das Eingabefeld für das zu validierende Attribut soll innerhalb einer Form sein: Html.BeginForm().
  • [OutputCache(Location = OutputCacheLocation.None, NoStore = true)]- dieses Attribut ist sehr wichtig! und muss vor der Validierungsmethode gesetzt werden, die JsonResult zurückgibt. Das verhindert, dass der Browser den Eingabewert im Cash speichert und die dynamische Validierung verhindert.
  • Der Parameter der Validierungsmethode muss den gleichen Namen haben wie das Attribut, dass validiert wird.
  • Es ist empfehlenswert, einen Parameter vom Typ string an die Validierungsmethode zu übergeben und den dann in den notwendigen Datentyp umzuwandeln. Dadurch vermeidet man, dass die Methode eine Exception auslöst, die nicht abgefangen und angezeigt werden kann.
  • Wenn Sie Ihrer Validierungsmethode mehr als nur einen Parameter übergeben möchten, benutzen Sie das AdditionalFieldsAttribut:
    [Remote("ActionName","ControllerName", AdditionalFields = "AddField1, AddField2")] Hier muss man auch beachten, dass die zusätzlichen Parameternamen mit den Modeleigenschaften übereinstimmen und sich auch in der View befinden. Dann bekommt die Validierungsmethode die zusätzlichen Parameter: public JsonResult ValidationMethod(.., string addField1, string addField2)

BEISPIEL:

Wir wollen in der Datenbank alle Romane eines bestimmten Schriftstellers speichern. Für die Eingabe gibt es eine Form. In eines der Eingabefelder soll der Titel eingetippt werden. Es soll ausgewertet werden, ob der eingegebene Titel bereits in der Datenbank vorhanden ist.

  1. <appSettings>
  2. <add key="ClientValidationEnabled"value="true"/>
  3. <add key="UnobtrusiveJavaScriptEnabled"value="true"/>
  4. </appSettings>


View:

  1. @using(Html.BeginForm()){
  2. @Html.ValidationSummary(true)
  3. <fieldset>
  4. <legend>AddNovel</legend>
  5.  
  6. <divclass="editor-label">
  7. @Html.LabelFor(model=>model.Titel)
  8. </div>
  9. <divclass="editor-field">
  10. @Html.EditorFor(model=>model.Titel)
  11. @Html.ValidationMessageFor(model=>model.Titel)
  12. </div>



Controller:

  1. [OutputCache(Location=OutputCacheLocation.None,NoStore=true)]
  2. publicJsonResultTitelErlaubt(stringtitel)
  3. {
  4. if(!_service.NovelExists(titel))
  5. {
  6. returnJson(true,JsonRequestBehavior.AllowGet);
  7. }
  8.  
  9. stringmeldung=String.Format("Roman {0} ist bereits in der Liste.",titel);
  10. returnJson(meldung,JsonRequestBehavior.AllowGet);
  11. }



Model:

  1. [Required]
  2. [Remote("TitelErlaubt","Home")]
  3. publicstringTitel{get;set;}



Das ist alles! In der Validierungsmethode wird überprüft, ob der Titel bereits vorhanden ist. Falls dies nicht der Fall ist, wird ein Json Objekt mit dem Wert true zurückgegeben. So wird jQuery mitgeteilt, dass kein Fehler aufgetreten ist. Fertig.

Falls der eingegebene Titel jedoch bereits in DB vorhanden ist, ist der Rückgabewert ein string – eine von Ihnen definierte Fehlermeldung, die dem Benutzer angezeigt wird; im Beispiel der Inhalt der Variablen „meldung“.

Welche Nachteile/Bedenken?

Wie vorher schon erwähnt wurde, wird die Validierung nach der ersten Fehleingabe „fleißig“ - es wird jeder Tastendruck in dem Eingabefeld ausgewertet. Das bedeutet bei jedem hinzugefügten oder gelöschten Zeichen wird eine Serveranfrage ausgelöst, was zu Lasten der Seiten-Performance geht.

Zum Glück gibt es hierfür eine Workaround-Lösung, die ich in einem Blog gefunden und ausprobiert habe:

  1. (function($){
  2. $.validator.setDefaults({
  3. onkeyup:function(element){
  4. if($(element).attr('data-val-remote-url')){
  5. returnfalse;
  6. }
  7. else{
  8. $(element).validate();
  9. return$(element).valid();
  10. }
  11. }
  12. })
  13. }(jQuery));



Das macht die Validierung wieder „faul“ – erst nach dem der Fokus das Eingabefeld verlässt tritt sie in Aktion, so wie am Anfang.

Nicht vergessen: Remote Validation funktioniert nur, wenn JavaScript erlaubt/aktiviert ist!

Viel Spaß!