Kickstarting validation in Umbraco

For this post, we're going to give you highly detailed, step by step guide on how to improve validation of forms within Umbraco. We'll be using jQuery and the jQuery Validate plugin, .NET's Data Annotations and serializing / deserializing data using JSON.

The example uses some of the advanced features of Umbraco and techniques that will be familiar to users of ASP.NET MVC. Ultimately, this tutorial will give you a solid foundation to allow you to easily pass information to the server, validate it and respond accordingly.

Ideally you'll have a local test project that you can use as a sandbox, so that you can play about and see how some of the techniques outlined will work. Alternatively, you can do what we did and start with a fresh install of Umbraco Web 4.7.2. We configured this fresh install to use SQL CE 4 using the "Simple Website" theme. Normally, we'd add code to a separate C# library, but for convenience, we've added code for this post in the App_Code folder.

Diving into the code

We're like you, sometimes we just want to see the code upfront... so here is a downloadable ZIP with everything you need to get going. You'll find the good stuff in the following folders;

  • /macroscripts/contactform.cshtml
  • /_assets/js/
  • /App_Code/

Note that we created our own masterpage for the contact form. This is because the theme we're using would have meant using nested forms.

DOWNLOAD THE UMBRACO EXAMPLE PROJECT (10Mb)

Adding Javascript Libraries

So, to start, let us add some javascript to our master page. These files will be the latest (and ideally minified) versions of jQuery, the jQuery Validate plug-in and JSON2.js. For those that are not familiar with JSON2, it creates a global JSON object containing two methods: stringify and parse. Note that modern browsers already have these methods for dealing with JSON. Also, the order of the files should be; jQuery, jQuery Validate and JSON2.

  <script src="/_assets/js/lib/jquery.min.js" type="text/javascript"></script>
  <script src="/_assets/js/lib/jquery.validate.min.js" type="text/javascript"></script>
  <script src="/_assets/js/lib/json2.js" type="text/javascript"></script>

Constructing the Form

For this demonstration, we'll be using a simple "Contact Us" form with some basic fields (of which some will be 'required fields'). We can create the form as a MacroScript using Razor which will allow us just enter some simple HTML.

<form id="contact-us">
    
    <fieldset>
        
        <h3>Your Details</h3>
        
        <p>
            <label for="Title">Title</label>
            <select id="Title" name="Title">
                <option value="Mr" selected="selected">Mr</option>
                <option value="Mrs">Mrs</option>
                <option value="Miss">Miss</option>
            </select>
        </p>

        <p>
            <label for="FirstName">First Name*</label>
            <input type="text" id="FirstName" name="FirstName">
        </p>
        
        <p>
            <label for="Surname">Surname*</label>
            <input type="text" id="Surname" name="Surname">
        </p>

For each of the fields, you'll need to ensure that you have an id and a name. These are required by the jQuery Validate plug-in. Once you have your fields set up, you'll need some HTML to display a "please wait" (for when we're processing the form) and somewhere to display the response after submitting the form to the server. We've used some inline styles to hide the content and style it, you should take the time to style up these elements properly for a better user experience.

    <p>
            <label for="Message">Message*</label>
            <textarea rows="5" cols="50" id="Message" name="Message"></textarea>
        </p>
        
        <input type="submit" value="Contact Us" />

    </fieldset>
    
    <p class="please-wait" style="display:none;">
        <img src="/_assets/images/loading.gif" /> Please wait...
    </p>
    
    <div class="response" style="margin-top:1em; display:none;">
        <h3 class="response-title"></h3>
        <p class="response-message"></p>
    </div>

</form>

Now we've got our form HTML ready to go, we can start adding some code. To reiterate, for convenience of this blog post we've simply added our code to the App_Code folder. We'd normally add any logic to a separate C# library and include that namespaced library via a post-build event.

DTO's and Data Annotation

In order to process the form on the server we want to create a Data Transfer Object (or DTO). We can then decorate the DTO with some basic .NET DataAnnotations. It's really important that the properties of the DTO match the name and id of the HTML element, so you have a property of "FirstName" and the HTML element has an id and name of "FirstName". If they do not match, you won't be able to deserialize the form into the DTO.

using System.ComponentModel.DataAnnotations;

namespace DataTransferObjects
{
    /// <summary>
    /// Summary description for ContactFormDto
    /// </summary>
    public class ContactFormDto
    {
        /// <summary>
        /// Title of the person, e.g. Mr, Mrs, Miss...
        /// </summary>
        public string Title { get; set; }

        /// <summary>
        /// First Name [Required]
        /// </summary>
        [Required(ErrorMessage = "Please enter your first name")]
        public string FirstName { get; set; }

        /// <summary>
        /// Surname [Required]
        /// </summary>
        [Required(ErrorMessage = "Please enter your surname")]
        public string Surname { get; set; }

To allow us to validate the DTO, we're going to borrow some of the basic code from the original xVal project by Steve Sanderson. This was the idea of using a DataAnnotiationsValidationRunner to run through all the properties on an instance and check the validity of the values of the properties using Data Annotatiations they were decorated with (don't worry to much about the code below, it works just fine!)

using System.Collections.Generic;
using System.Linq;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;

namespace DataValidation
{
    public static class DataAnnotationsValidationRunner
    {
        public static IEnumerable<ErrorInfo> GetErrors(object instance)
        {
            return from prop in TypeDescriptor.GetProperties(instance).Cast<PropertyDescriptor>()
                   from attribute in prop.Attributes.OfType<ValidationAttribute>()
                   where !attribute.IsValid(prop.GetValue(instance))
                   select new ErrorInfo(prop.Name, attribute.FormatErrorMessage(string.Empty), instance);
        }
    }
}

So, we now have a method that will check an instance and return an enumerable list of ErrorInfo instances. The ErrorInfo class simply consists of a PropertyName, ErrorMessage and Instance;

namespace DataValidation
{
    public class ErrorInfo
    {
        public ErrorInfo(string propertyName, string errorMessage, object instance)
        {
            PropertyName = propertyName;
            ErrorMessage = errorMessage;
            Instance = instance;
        }

        public string PropertyName { get; set; }
        public string ErrorMessage { get; set; }
        public object Instance { get; set; }
    }
}

POSTing data to the server

With our basic JS libraries, Validation and HTML set up, we can now consider how to pass the form input to the server and validate it. The easiest way to do this is via the RESTful interface that Umbraco provides. It's fairly trivial to set up a simple class and decorate it with the interface methods;

namespace Rest
{
    [RestExtension("Validation")]
    public class Base
    {

        private static readonly JavaScriptSerializer Serializer = new JavaScriptSerializer();
        
        [RestExtensionMethod(returnXml = false)]
        public static string ContactForm()
        {

This will give us the url of /base/Validation/ContactForm where we can post data to. Now we have a place on the server that we post the data, process the form and pass back a response.

We still need to pass the data to the server though, so let's leverage the power of jQuery and its AJAX methods to help us. We'll need to create and add a new "contact-form.js" file in which we can add some javascript methods that will help us. The basic idea is to serialize the form data and POST it to the server in a string of JSON. To do this, we can extend jQuery with a simple serializeObject function that will run through the form elements and create a key / value pair for each element.

/*
* handy jQuery serializeObject extension
* usage : $("#myForm").serializeObject();
*/
$.fn.serializeObject = function () {
    var o = {};
    var a = this.serializeArray();
    $.each(a, function () {
        if (o[this.name]) {
            if (!o[this.name].push) {
                o[this.name] = [o[this.name]];
            }
            o[this.name].push(this.value || '');
        } else {
            o[this.name] = this.value || '';
        }
    });
    return o;
};

It's a common practise to start using jQuery to manipulate the DOM via a handler when its loaded (usually referred to as "on document ready"). It's considered best practise to create some variables to hold jQuery references to DOM elements. This stops repeated calls to find elements in the DOM thus speeding up execution.

/*
* Document Ready
*/

$(function () {

    var contactForm = $("#contact-us");
    var pleaseWait = $(".loading");

    var response = $(".response");
    var responseTitle = $(".response-title");
    var responseMessage = $(".response-message");

So, for our example, we need to initialise the form and set up some basic parameters for the jQuery Validate to fire when the submit button is pressed. It's important to attach the instance of the jQuery Validate to our jQuery form reference (highlighted).

   /*
    * Initialise the Contact Form
    */
    var initContactForm = function () {

        contactForm.validator = contactForm.validate({

            // this is the html element that will wrap error messages
            errorElement: "span",

            // this is where we'll place the error message
            errorPlacement: function (error, element) {
                error.appendTo(element.parent());
            },

            // set up form submit event
            submitHandler: submitContactForm

        });

    };

For the submitHandler we've created a single function (submitContactForm) that will POST the data to server. Note how were using the JSON.stringify and contactForm.serializeObject to create a string of JSON from the form elements. This string is what will get passed to the server.

/*
 * Submit the Contact Form via AJAX
 */
var submitContactForm = function () {

	// show the fact the form is loading;
	pleaseWait.show();
	response.hide();
	responseTitle.empty().hide();
	responseMessage.empty().hide();

	// now serialize the form data;
	var json = JSON.stringify(contactForm.serializeObject());

	// post to server
	$.ajax({
	    type: "POST",
	    url: "/base/Validation/ContactForm",
	    data: json,
	    success: function (formResultDto) {

		// do stuff

	    }
	});
	
}

Below is an example of the stringify'd JSON that will be passed to the server;

json string

Validation on the server

Now that we've passed the string to the server (to our "base" Validation.ContactForm method), we need to deserialize it into a contactFormDto instance and then validate that instance. First we grab the string from the Form object and then attempt to deserialize it. This is done by the native .NET JavaScriptSerializer and telling it to deserialize the string into our ContactFormDto type.

contact dto deserialized


Next we check for any errors. If there are errors we create a simple FormResultDto, that consists of a Title, Message and an enumerable list of ErrorInfo instances. This will be serialized and sent back to the client.

// create a response that will be serialized and sent back
var formResponse = new FormResultDto();

// grab the json from Form object
var json = HttpContext.Current.Request.Form[0];
            
// try and deserialize
var contactFormDto = Serializer.Deserialize<ContactFormDto>(json);
if ( contactFormDto != null )
{
   // try and validate;
   var errors = DataAnnotationsValidationRunner.GetErrors(contactFormDto);
   if (errors.Any()) {
         formResponse.Title = "Sorry";
         formResponse.Message = "Please ensure you've entered all the fields correctly";
         formResponse.Errors = errors;
         return Serializer.Serialize(formResponse);
   }
}

Now, of course, if there were no errors, you can continue processing your data. At this point, your form info is nicely wrapped up in a handy DTO instance, this means you can pass it further down into your business logic or data layers. Sweet.

At this point, after successful validation, you'll just pass back a 'successful' FormResultDto.

// after processing, let the user know what's up
formResponse.Title = "Thank you";
formResponse.Message = "Your details were submitted successfully. You'll hear from us soon.";
formResponse.Errors = null;
return Serializer.Serialize(formResponse);

Dealing with the response

So, back over on the client, we need to show the response from the server. We can do this within the success method of our original AJAX request. Now we deserialize the formResultDto on the client using jQuery parseJSON method. Based on the response we can then show errors and / the message.

// post to server
$.ajax({
    type: "POST",
    url: "/base/Validation/ContactForm",
    data: json,
    success: function (formResultDto) {

	var formResult = $.parseJSON(formResultDto);

	// got errors?
	if (formResult.Errors != null) {
	    showErrors(formResult.Errors);
	};

	// got message?
	if (formResult.Title != null && formResult.Message != null) {

	    pleaseWait.hide();

	    response.show();
	    responseTitle.show().text(formResult.Title);
	    responseMessage.show().text(formResult.Message);

	}

    }
});

If we need to show the errors, we can pass the errors back to the validator to show. We can also work out what the first error is and set the form to focus on it, giving a better usability experience for the user.

/* 
* Show Errors
*/
var showErrors = function (formErrors) {

	var e = {};
	var firstError = "";

	for (var i in formErrors) {
		var error = formErrors[i];
		if (i == 0) firstError = error.PropertyName;
		e[error.PropertyName] = error.ErrorMessage;
	}

	contactForm.validator.showErrors(e);
	$("#" + firstError).focus();

};

Finally you'll see the errors displayed neatly under the form elements.

contact form errors

Taking it further...

So, the above steps provide a really neat way of passing form data to the server, wrapping it up in some simple instances and dealing with processing and validation. You could now take the example further by perhaps improving on the following;

  • Extending the jQuery Validate initialization to include rules and messages for clientside validation
  • Using addtional HTML5 attributes for the form elements
  • Use some more of the Data Annotations to decorate your properties, for example, Range or RegEx Attributes
  • It doesn't have to necessarily be form information that you pass back to the server, it could be from some other UI interaction, such as sending latitude and longitude to update a map in real time, or perhaps some other form of look-up
  • Implement better error handling for production use

We hope that you've learnt something from the guide above and of course, if you spot any errors, please let us know.

blog comments powered by Disqus

Post Tags Blog posts by tag

By specific tag:designdevelopmentxsltxslUmbracoaspsearch enginesdeveloper toolssvnOptimisationCSSKilnJust for funBrowsersFogBugzHow to be a clientTwitterDebuggingUser ExperienceJavascriptEcommerceResourcesmercurialbest practisescodingtestingimagegen

Latest comments Latest Comments