MVC3 klient og servervalidering med jquery-validation og validationatributter

Hvis man har arbejdet lidt med ASP.NET MVC3 og formularer, kender man givetvis "validationattributes", der bla. giver let adgang til validering af om et felt er udfyldt eller om værdien ligger indenfor et interval osv. Der findes en håndfuld i MVC3 som man får serveret på et sølvfad.

Hvis du er i tvivl om hvad jeg snakker om, så ser det nogenlunde således ud i modellen:

public class Person
{
   [Required]
   public string Navn { get; set; }

   [Required]
   public string Adresse { get; set; }
}

Formularen kunne se således ud i View:

@model Person

@using(Html.BeginForm())
{
   @Html.LabelFor(m => m.Navn)<br/>
   @Html.EditorFor(m => m.Navn)<br/>
   @Html.ValidationMessageFor(m => m.Navn)<br/>
   
   @Html.LabelFor(m => m.Adresse)<br/>
   @Html.EditorFor(m => m.Adresse)<br/>
   @Html.ValidationMessageFor(m => m.Adresse)<br/>
   <br/>
   <button type="submit">Gem</button>
}

Dette vil, ved postback, resultere i en validering, på serveren, af om Navn og Adresse indeholder noget (som ikke er en tom streng eller mellemrum). Hvis den ikke er gyldig, vises standardfejlbeskeden for Required i de felter som Html.ValidationMessageFor genererer.

Hvis man ønsker at få valideret sin formular på klienten, kan man blot inkludere jQuery basis biblioteket, samt jquery.validate og jquery.validate.unobtrusive i forbindelse med formularen, eller i basis-layoutet, hvis man har mange formularer på sit site. Noget i stil med dette:

<script src="/scripts/jquery-1.7.2.min.js"></script>
<script src="/scripts/jquery.validation.min.js"></script>
<script src="/scripts/jquery.validation.unobtrusive.min.js"></script>

Med disse inkluderet i siden med formularen, skulle valideringen allerede ske inden data sendes til serveren og det er jo ofte en god ting (for brugeren og for din server).

Der findes, som standard, 5 valideringsatributter i MVC, der spiller sammen med jquery.validate. Disse er:

  • Required (som vist tidligere)
  • StringLength
  • Range
  • RegularExpression
  • Compare.

jquery.validate har yderligere 6 i værktøjskassen, nemlig: 

  • Email
  • Url
  • Date
  • Number
  • Digits
  • Creditcard

Disse er dog ikke umiddelbart tilgængelige som server validationatributter, så hvis man vil have mere valideringsfunktionalitet end de 5 første, må man til at strikke sine egne atributter sammen. Det er nu heller ikke så galt endda!

Egne klient/server valideringsatributter

Alle valideringsatributter bør nedarve fra ValidationAttribute, det kommer dem jeg laver i det mindste til. Hvis vi gør det, kan vi lave en ny regel, der validerer om et felt indeholder en emailadresse, med følgende kode:

public class EmailAddressAttribute : ValidationAttribute
{
   private static readonly Regex rxEmail = 
         new Regex("^\\S+@(\\S+\\.)+\\S+$");

   public EmailAddressAttribute()
   {
      ErrorMessage = "Please enter a valid email address.";
   }

   public override bool IsValid(object value)
   {
      if (value == null)
         return false;

      string v = (value as string).Trim();
      return !String.IsNullOrEmpty(v) && rxEmail.IsMatch(v);
   }
}

Med dette kode, har vi en validationattribute vi kan bruge i vores model og dermed få validering af e-mailadresser.

public class Person
{
   [Required]
   public string Navn { get; set; }

   [Required]
   public string Adresse { get; set; }

   [EmailAddress]
   public string Email { get; set; }
}

Som man kan se er der sat validering på det nye Email-felt i Person-klassen. Der er dog ikke klientvalidering på Email-feltet endnu, så det må vi hellere få lagt på.

Dette gøres ved at implementere interfacet IClientValidatable, hvilket kunne gøres nogenlunde således:

public class EmailAddressAttribute : ValidationAttribute
                                   , IClientValidatable
{
   // ... valideringskoden fra før ...

   public IEnumerable<ModelClientValidationRule> 
      GetClientValidationRules(
         ModelMetadata metadata,
         ControllerContext context
      )
   {
      return new List<ModelClientValidationRule> {
         new ModelClientValidationRule {
            ValidationType = "email",
            ErrorMessage = this.ErrorMessage
         }
      };
   }
}

Med denne kode kan vi nu forvente at der sker en validering af Email-feltet på formularen, både på klienten og på serveren (forudsat vi har placeret feltet på vores View efter samme metode som for Navn og Adresse).

Hvis man har særlige valideringsbehov, kan man også udvide jquery.validator med nye valideringsrutiner. Dette vil jeg dog lade vente til en anden artikel.

NB: Beklager den lidt spøjse formatering af koden, men sidelayoutet bød mig at gøre et eller andet for at holde styr på den kodeeksemplerne :-)

Comment