Benutzereingaben prüfen mit ASP.NET Core

Eine der wesentlichen Bestandteile einer Geschäftsanwendung (LOB) ist die Input Validierung. Der ASP.NET Webforms Entwickler kennt und nutzt verschiedene Validator Controls die sich deklarativ binden lassen. Der WPF Entwickler setzt vermutlich im MVVM Model auf Dataannotations. Diese nutzen Attribute über den Propertys einer Model Klasse. Das UI wertet die automatisch aus um den User auf die Finger zu klopfen. Etwas was dem UWP Entwickler unerklärlicherweise bis heute verwehrt bleibt. Kein Support für Data Annotations in UWP. Der Web Entwickler wiederum hat das Problem, das er den Job zweimal machen muss. Am Client, dem Browser, um dem Benutzer bei der Eingabe zu unterstützen und am Server um schlimmes zu verhindern.

Attribute werden auch mehrfach auf jede Eigenschaften deklariert. Optionale Parameter helfen, bezüglich Wertemengen oder Fehlermeldungen. Diese Art von Attributen stammen aus dem Namensraum System.ComponentModel.DataAnnotations. EmailAddress zwingt das gebundene UI dazu das HTML Type Email zu rendern. Die Eigentliche Prüfung auf gültige Email muss allerdings per RegEx erledigt werden. Ein Sonderfall stellt die Remote Validierung dar, kommt später im Text.

   1:  public class Benutzer
   2:  {
   3:    [Required]
   4:    [StringLength(10, MinimumLength = 5)]
   5:    public string Name { get; set; }
   6:   
   7:    [Required]
   8:    [StringLength(2)]
   9:    public string Land { get; set; }
  10:   
  11:    [Remote(action:"ValidateEmail", controller: "RemoteValidate", HttpMethod ="Post",
  12:  ErrorMessage = "Please enter a valid email extension."
  13:  ]
  14:    [EmailAddress]
  15:    [RegularExpression(@"[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?",ErrorMessage ="keine email")]
  16:    public string Email { get; set; }
  17:  }

 

Im HTML Code der Razor Page erkennt man schon fast Ähnlichkeiten zum z.B ValidationSummary Control, das hier per Tag Helper eingestreut wird, genauso wie die Fehlerhinweise.

   1:  <form method="post">
   2:      eMail:<input asp-for="PageBenutzer.Email" />   
   3:  <span asp-validation-for="PageBenutzer.Email"></span><br />
   4:      Land:<input asp-for="PageBenutzer.Land" />  
   5:   <span asp-validation-for="PageBenutzer.Land"></span><br />
   6:      Name:<input asp-for="PageBenutzer.Name" />   
   7:  <span asp-validation-for="PageBenutzer.Name"></span><br />
   8:      <button>send</button>
   9:      <div asp-validation-summary="All">
  10:          <span>Eingabefehler korrigieren</span>
  11:      </div>
  12:  </form>

 

image

Soweit würde das im Prinzip wie dargestellt funktionieren. Nach einem Post, validiert am Web Server. Um auch die JavaScript Unterstützung und damit eine Client Seitige Adhoc Validierung braucht man wie üblich JavaScript Bibliotheken.

   1:  <script src="~/lib/jquery-validation/dist/jquery.validate.js"></script>
   2:  <script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js"></script>

Das ganze setzt auf dem Data Binding Mechanismus einer Razor PageModel Klasse auf. Die Personen Klasse wird als Property angelegt und per BindProperty (oder BindProperties) in diesen Automatismus eingebunden. Per Konvention löst ein Post die OnPost Methode aus, in der das Model nocheinmal geprüft wird. In OnPost ist das Objekt PageBenutzer mit den Daten aus dem Formular, das der Benutzer gefüllt hat, belegt.

   1:  [BindProperty]
   2:  public Benutzer PageBenutzer { get; set; }
   3:   
   4:  public IActionResult OnPost()
   5:   {
   6:       if (ModelState.IsValid)
   7:        {
   8:         return RedirectToPage("Contact");
   9:         }
  10:         else
  11:         {
  12:          return Page();
  13:         }

Leider kann man nicht in die Razor Page Klasse auch den Callback Code für dem Remote Validator einfügen. Es braucht einen klassischen MVC Controller im Controllers Verzeichnis (bei Bedarf anlegen). Um dem System den Controller auch bekannt zu machen, setzt man auf Routing. Razor Pages versuchen per Konvention zu arbeiten. Das reicht hier nicht und wirft ggf einen Fehler, wenn die Route nicht vorhanden ist. Man könnte und die meisten tun das in der Startup Klasse ein Routen Konvolut anlegen oder man nimmt wieder einmal ein Attribut.

   1:  public class RemoteValidateController : Controller
   2:    {
   3:          [HttpPost("ValidateEmail")]
   4:          public IActionResult ValidateEmail([Bind(Prefix = "PageBenutzer.Email")] string email)
   5:          {
   6:              if (email.Contains(".de"))
   7:              {
   8:                  return new JsonResult(true);
   9:              }
  10:              return new JsonResult($"Email {email} use .de");
  11:          }
  12:  }

Was mir nicht gefällt:

Der Controller RemoteValidate samt genauer Route muss im Model Person fest verdrahtet werden. Genauso muss der Controller an das Property aus dem Page Model Property gebunden per Bind werden um den Wert zu erhalten. Vielleicht übersehe ich heute noch eine einfachere Lösung für Validierung mit ASP.NET core Razor View Engine.

Kommentare sind geschlossen