Unobtrusive validation in ASP.NET MVC 3
In ASP.NET MVC 2 we got support for client validation of the model. When we activate it, a JavaScript is generated and added to the rendered view. It contains all validation rules we set up for the model, and are used to generate error massages without reloading the page.
I ASP.NET MVC 3 they have extended that support. Instead of generating a JavaScript, you can now use ”unobtrusive Jquery validation”, which uses the data-* attribute in HTML5 instead of using JavaScript.
To activate it on the page you can add this:
@Html.EnableUnobtrusiveJavaScript()
And to activate it on all pages, you can add a key to web.config:
<appSettings>
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
</appSettings>
New ASP.NET MVC 3 Beta projects will have this enabled as default, and upgraded projects will not have it activated as default to make sure it is backwards compatible.
To use this new validation, you will have to add references to jquery-1.4.1.js, jquery.validate.js and jquery.validate.unobtrusive.js.
To test this, I have a model, ”Customer”, which looks like this:
using System;
using System.ComponentModel.DataAnnotations;
namespace MyMvc3Site.Models
{
public class Customer
{
[Required]
public int CustomerId { get; set; }
[Required]
[StringLength(5)]
public string Name { get; set; }
[Required]
public DateTime Birthday { get; set; }
}
}
In the view, I have this:
@model MyMvc3Site.Models.Customer
@{
View.Title = "Create";
}
<h2>Create</h2>
@using (Html.BeginForm()) {
@Html.ValidationSummary(true)
<fieldset>
<legend>Fields</legend>
<div class="editor-label">
@Html.LabelFor(model => model.CustomerId)
</div>
<div class="editor-field">
@Html.TextBoxFor(model => model.CustomerId)
@Html.ValidationMessageFor(model => model.CustomerId)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Name)
</div>
<div class="editor-field">
@Html.TextBoxFor(model => model.Name)
@Html.ValidationMessageFor(model => model.Name)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Birthday)
</div>
<div class="editor-field">
@Html.TextBoxFor(model => model.Birthday)
@Html.ValidationMessageFor(model => model.Birthday)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
Without unobtrusive jQuery validation, we will get this in the view:
<form action="/Customer/Create" id="form0" method="post"><div class="validation-summary-valid" id="validationSummary"><ul><li style="display:none"></li>
</ul></div> <fieldset>
<legend>Fields</legend>
<div class="editor-label">
<label for="CustomerId">CustomerId</label>
</div>
<div class="editor-field">
<input id="CustomerId" name="CustomerId" type="text" value="" />
<span class="field-validation-valid" id="CustomerId_validationMessage"></span>
</div>
<div class="editor-label">
<label for="Name">Name</label>
</div>
<div class="editor-field">
<input id="Name" name="Name" type="text" value="" />
<span class="field-validation-valid" id="Name_validationMessage"></span>
</div>
<div class="editor-label">
<label for="Birthday">Birthday</label>
</div>
<div class="editor-field">
<input id="Birthday" name="Birthday" type="text" value="" />
<span class="field-validation-valid" id="Birthday_validationMessage"></span>
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
</form><script type="text/javascript">
//<![CDATA[
if (!window.mvcClientValidationMetadata) { window.mvcClientValidationMetadata = []; }
window.mvcClientValidationMetadata.push({"Fields":[{"FieldName":"CustomerId",
"ReplaceValidationMessageContents":true,"ValidationMessageId":"CustomerId_validationMessage",
"ValidationRules":[{"ErrorMessage":"The CustomerId field is required.","ValidationParameters":{},
"ValidationType":"required"},{"ErrorMessage":"The field CustomerId must be a number.",
"ValidationParameters":{},"ValidationType":"number"}]},{"FieldName":"Name",
"ReplaceValidationMessageContents":true,"ValidationMessageId":"Name_validationMessage",
"ValidationRules":[{"ErrorMessage":"The Name field is required.","ValidationParameters":{},
"ValidationType":"required"},{"ErrorMessage":"The field Name must be a string with a maximum length of 5.",
"ValidationParameters":{"max":5},"ValidationType":"length"}]},{"FieldName":"Birthday",
"ReplaceValidationMessageContents":true,"ValidationMessageId":"Birthday_validationMessage",
"ValidationRules":[{"ErrorMessage":"The Birthday field is required.","ValidationParameters":{},
"ValidationType":"required"}]}],"FormId":"form0","ReplaceValidationSummary":false,"ValidationSummaryId":"validationSummary"});
//]]>
</script>
It is a lot of JavaScript being rendered, and if we activate unobtrusive jQuery validation, we will get this instead:
<form action="/Customer/Create" method="post"> <fieldset>
<legend>Fields</legend>
<div class="editor-label">
<label for="CustomerId">CustomerId</label>
</div>
<div class="editor-field">
<input data-val="true" data-val-number="The field CustomerId must be a number." data-val-required="The CustomerId field is required." id="CustomerId" name="CustomerId" type="text" value="" />
<span class="field-validation-valid" data-valmsg-for="CustomerId" data-valmsg-replace="true"></span>
</div>
<div class="editor-label">
<label for="Name">Name</label>
</div>
<div class="editor-field">
<input data-val="true" data-val-length="The field Name must be a string with a maximum length of 5." data-val-length-max="5" data-val-required="The Name field is required." id="Name" name="Name" type="text" value="" />
<span class="field-validation-valid" data-valmsg-for="Name" data-valmsg-replace="true"></span>
</div>
<div class="editor-label">
<label for="Birthday">Birthday</label>
</div>
<div class="editor-field">
<input data-val="true" data-val-required="The Birthday field is required." id="Birthday" name="Birthday" type="text" value="" />
<span class="field-validation-valid" data-valmsg-for="Birthday" data-valmsg-replace="true"></span>
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
</form>
Instead of JavaScript, the different elements will have a couple of new attributes instead. Jquery.validation.unobtrusive.js contains functionality that can parse these values and generates error messages based on these instead. In this way, we will get much cleaner HTML, and still have valid HTML5. The validation will work exactly like before, the only difference is what is being rendered.