In Listing 22 we referenced the jQuery library files from the ~/Scripts folder of our application.
An alternative approach is to load these files from the Microsoft Ajax Content Delivery Network (CDN). This is a free service that Microsoft provides – there are a set of geographically distributed servers which will service requests for the MVC JavaScript library files using the server which is closest to each user.
There are a number of benefits to using the CDN. Firstly, the time it takes for the user’s browser to load the application can be reduced, because the CDN servers are faster and closer to the user than the applications servers – this benefit is compounded if the user has already obtained the required files in the browser cache by using another application that requires the same files taken from the same CDN.
The second benefit is that it reduces the server capacity and bandwidth that we have to provision to deliver our application. The jQuery files are usually some of the largest items to be delivered to the browser in an MVC application and have the browser obtain these from Microsoft’s servers can help keep operational costs down. To take advantage of the CDN, we have to change the src attributes of our script elements to reference the following URLs:
http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.5.1.min.js
http://ajax.aspnetcdn.com/ajax/jquery.validate/1.7/jquery.validate.min.js http://ajax.aspnetcdn.com/ajax/mvc/3.0/jquery.validate.unobtrusive.min.js
So, for example, the script element that references the core jQuery library becomes:
<script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.5.1.min.js"
type="text/javascript"></script>
The CDN servers host multiple versions of each of the jQuery libraries, so we have to select the correct URL for each file. You can see the full set of files that are available (and their URLs) here:
http://www.asp.net/ajaxlibrary/cdn.ashx
The CDN service is useful for internet-facing applications, but if your project is for an intranet, then you will find that the CDN isn’t much help – if will generally be quicker and cheaper to have your clients obtain the JavaScript libraries from the application server.
Using Client-Side Validation
Once we have enabled client-side validation and ensured that the jQuery libraries are referenced in our view, we can start to perform client-side validation. The simplest way of going this is to apply the metadata attributes that we previously used for server-side validation, such as Required, Range and StringLength. Listing 23 shows our Appointment model class with these annotations applied.
Listing 23. Validation attributes applied to the Appointment model object public class Appointment {
[Required]
[StringLength(10, MinimumLength=3)]
public string ClientName { get; set; } [DataType(DataType.Date)]
[Required(ErrorMessage="Please enter a date")]
public DateTime Date { get; set; } public bool TermsAccepted { get; set; } }
You can learn more about these attributes in the Specifying Validation Rules Using Metadata section earlier in this chapter. Client-side validation displays validation errors slightly differently when using validation summaries and validation messages, so we have updated the MakingBooking view to use both, as shown in Listing 24.
Listing 24. Adding per-input element validation summaries to an HTML form
@model MvcApp.Models.Appointment
@{
ViewBag.Title = "Make A Booking";
}
<h4>Book an Appointment</h4>
@using (Html.BeginForm()) { @Html.ValidationSummary()
<p>Your name: @Html.EditorFor(m => m.ClientName) @Html.ValidationMessageFor(m => m.ClientName)</p>
<p>Appointment Date: @Html.EditorFor(m => m.Date) @Html.ValidationMessageFor(m => m.Date)</p>
<p>@Html.EditorFor(m => m.TermsAccepted) I accept the terms & conditions
@Html.ValidationMessageFor(m => m.TermsAccepted)</p>
<input type="submit" value="Make Booking" />
}
When we make a request that invokes the MakeBooking action method in our controller, we render the MakeBooking.cshtml view – all standard stuff. However, when we press the submit button, the validation rules we have added to the Appointment class are applied in the browser using JavaScript, as shown in Figure 10.
Figure 10. Client-side validation error messages
The validation errors that are displayed look identical to the ones that server-side validation produces, but they are generated without making a request to the server. If you are running the browser and the server on a single development machine, it can be hard to spot a speed difference – but over the internet or a busy corporate intranet, the difference is huge.
There is another difference as well – the client-side validation is first performed when the user submits the form, but it is then performed again every time the user presses a key or changes the focus on the HTML form. We typed the letter J into the ClientName field, which satisfies the Required attribute that we applied to the corresponding property in the Appointment class.
However, now we are in violation of the StringLength attribute we applied – as the validation message next to the input field shows in Figure 11.
Figure 11. Client-side validation errors are updated automatically
The error message alongside the field has changed. We didn’t have to take any special steps to make this happen – we just typed a character into the input field. The client-side validation was performed again and the new error was displayed.
Tip Notice that the validation summary that we created with the Html.ValidationSummary helper hasn’t changed – it won’t be updated until we press the Make Booking button again. This is what we meant when we said that the summary works differently to the per-field messages when using client-side validation.
We continue typing and when we get to the e in Joe, we have satisfied both of the validation rules that we applied to the ClientName property in the Appointment class – a value has been provided and it is between three and ten characters. At this point, the error message alongside the input field disappears and the highlighting for the field is removed, as shown in Figure 12.
Figure 12. Validation error messages are cleared automatically
Not only does the user get immediate feedback when there is a validation error, but the error status is updated as the user types. This is hard to express in a series of screenshots, but it is a much more compelling way of validating form data – not only does it give the user a better experience, but it means that fewer POST requests are made to the application server for us to process. Once we have a satisfactory value for the ClientName property, we submit the form again. It is only at this point that the validation summary is updated, as shown in Figure 13.
Figure 13. Submitting the form updates the validation summary
The less frequent updates make the validation summary less attractive to the user than per-input messages, especially when multiple validation rules are associated with a field. That doesn’t mean that we should not use the summary approach, but we should do so carefully, considering the effect it will have on the user experience.
Understanding How Client-Side Validation Works
One of the benefits of using the MVC framework client-side validation feature is that we don’t have to write any JavaScript. Instead, the validation rules are expressed using HTML attributes.
Here is the HTML that is rendered by the Html.EditorFor helper for the ClientName property when client-side validation is disabled:
<input class="text-box single-line" id="ClientName" name="ClientName"
type="text" value="" />
When we switch on the validation and render the editor, we see these additions:
<input class="text-box single-line" data-val="true" data-val-length="The field ClientName must be a string with a minimum length of 3 and a maximum length of 10." data-val-length-max="10" data-val-length- min="3" data-val-required="The ClientName field is required."
id="ClientName" name="ClientName" type="text" value="" />
The MVC client-side validation support doesn’t generate any JavaScript or JSON data to direct the validation process – like much of the rest of the MVC framework, we rely on convention.
The first attribute that was added is data-val – the validation library identifies those fields which require validation by looking for this attribute.
Individual validation rules are specified using an attribute in the form data-val-<name>, where name is the rule to be applied. So, for example, the Required attribute we applied to the model class has resulted in a data-val-required attribute in the HTML. The value associated with the attribute is the error message associated with the rule. Some rules require additional
attributes – you can see this with the length rule, which has data-val-length-min and data-val- length-max attributes to let us specify the minimum and maximum string lengths that are allowed.
The interpretation of the required and length validation rules is provided by the jQuery Validation library, on which the MVC client validation features are built.
Once of the nice features about the MVC client-side validation is that the same attributes we use to specify validation rules are applied at the client and at the server. This means that data from browsers that don’t support JavaScript are subject to the same validation as those that do, without requiring us to make any additional efforts.