Client-Side Validation Using xVal and ASP.NET MVC 2

Validating input on the server-side in ASP.NET MVC 2 is quite easy when using the new Data Annotations on our Model classes. It means that we have automatic validation every time someone submits data to our Controller, the model binder of ASP.NET MVC will take care of running the validation rules we set up in the model.

However the problem arises when we want client side validation on our model. We don’t want to repeat our validation rules to a client side library as that will be a pain in the ass to maintain later, when the model changes. What we do want is something that is using our preexisting rules in a way that the client side library understands.

This is where xVal enters the game. It does exactly what I just described, which is converting our Data Annotation attribute-rules to rules which the excellent jQuery Validation plugin can understand. To give an example of how you can implement xVal with ASP.NET MVC, I will create a user registration form which will feature a few standard validation rules.

Validating a user registration form

Begin with downloading xVal library from CodePlex and reference the file from our new and empty ASP.NET MVC 2 project in Visual Studio. Also add the xVal.jquery.validate.js file to our scripts folder. We need a user class to play with. Add a class named User in the Models folder and add the following code.

[MetadataType(typeof(UserMetadata))]
public class User {
    public string Username { get; set; }
    public string Password { get; set; }
    public string Email { get; set; }
    public string Name { get; set; }

    private class UserMetadata {
        [Required, StringLength(30)]            
        public object Username { get; set; }

        [Required, StringLength(30)]
        public string Password { get; set; }

        [Required, DataType(DataType.EmailAddress)]
        public object Email { get; set; }
    }
}

This will require a user to enter a username, password and email address. Username and password will require a maximum of 30 characters long and the name field will be optional.

We got the model, but we need somewhere to store them. For this simple demo I will be creating a dummy repository class which saves the user objects in memory, like the following snippet.

public class UserRepository {
    readonly List<User> _users = new List<User>();

    public void Create(User user) {
        // Save to database
        _users.Add(user);
    }
}

Now we need a controller and actions for our registration form. Two Register actions will be created – one for the GET and one for the POST. The GET will simply return a View and display a registration form, with the fields of our model. When submitting the form we will get to our POST action method which will check the ModelState.IsValid property if the input data is valid, if not the method will return the View, with supplied data. Otherwise the user object is saved to our dummy database and the user is redirected to the success page.

public ActionResult Register() {
    return View();
}

[HttpPost]
public ActionResult Register(User user) {
    if (!ModelState.IsValid)
        return View(user);

    _userRepository.Create(user);

    return RedirectToAction("Registered");
}

public ActionResult Registered() {
    return View();
}

If you have created the View files for these actions you should be having a fully functional registration form, with server-side validation.

Magically turn on client-side validation

The server-side validation is working, and all we ever want now is client-side validation! The steps to make that work is so easy it is laughable. We only need to include these script files in the head section.

<script src="/scripts/jquery-1.4.2.min.js" type="text/javascript"></script>
<script src="/scripts/jquery.validate.js" type="text/javascript"></script>
<script src="/scripts/xval.jquery.validate.js" type="text/javascript"></script>

Client Side Validation with xValLastly we need to tell xVal to output the Data Annotation rules to our page, so that it can be read by JavaScript. This is very easily done with the following HtmlHelper method, at the bottom of our View page:

<%= Html.ClientSideValidation<User>() %>

That’s all!? Yes, in fact that is all we have to do, to get client-side validation in ASP.NET MVC 2. Try it out, and then get back here to see what more ways you can customize xVal.

Remote validation

Sometimes only client-side validation is not enough to validate certain properties of a model. We need to validate business rules which uses a database to validate. In these cases it can be really useful to move the validation back to the server, but still keeping the snappy, instant validation that client-side validation gives us.

In xVal this is possible through something that is called RemoteRule. To create a Remote Rule you only need to create a new Action method in your Controller, which receives the model, validates it, and finally returns a true/false result. In our project we will check if a username is already taken, so that two users can’t have the same username. We will start with the following Action method:

public RemoteValidationResult UsernameIsTaken(User user) {
    var exists = _userRepository.ExistsUsername(user.Username);
    return exists
        ? RemoteValidationResult.Failure("Username is already taken.")
        : RemoteValidationResult.Success;
}

I also updated the UserRepository class to include an ExistsUsername method which returns true if the username starts with “yadda”.

To register the Remote Rule with xVal we need to open the “Register” view and find the ClientSideValidation method we used earlier, and run a method on the returned object.

<%= Html.ClientSideValidation<User>()
    .AddRule("Username", new RemoteRule(Url.Action("UsernameIsTaken"))) %>

Remote Validation is now hooked up and you can try it out by typing “yadda” in the username field. It should then say the username is taken when you tab out of the field. Awesomely easy!

Custom attributes with client-side validation

In those cases where you do not need remote validation but only classic JavaScript validation will do just fine, then creating a new Data Annotation attribute is a good idea. We will use this technique when validating if a password is good-enough for us.

We will start with a new class, that inherit from ValidationAttribute (from Data Annotation) and implements the ICustomRule interface (from xVal). From the inherited class you will override the IsValid method which does the actual validation. In this case we will use Regular Expressions to determine if the password is decent. The other method, which we got from the ICustomRule interface will tell xVal which JavaScript function to run when doing the client-side validation. I have named it “GoodPassword”, and it won’t receive any parameters (null). If the validation fails, it will use the error message set in the constructor.

public class GoodPasswordAttribute : ValidationAttribute, ICustomRule {
    public GoodPasswordAttribute() {
        ErrorMessage = "Enter a better password.";
    }

    public override bool IsValid(object value) {
        if (!(value is string))
            return false;

        // Requires passwords to have atleast 5 chars and one number
        return Regex.IsMatch(value.ToString(), @"^.*(?=.{5})(?=.*\d)(?=.*\w).*$");
    }

    public CustomRule ToCustomRule() {
        // First parameter is the JavaScript function name
        return new CustomRule("GoodPassword", null, ErrorMessage);
    }
}

Finally the last thing is implementing the JavaScript function, which will use the same regex pattern as the server-side. The pattern could have been sent over to the JavaScript function through a parameter, but I wanted to keep them separate incase the JavaScript version needed modifications. Following is the last snippet showing the final JavaScript function.

function GoodPassword(value, element, params) {
    var regex = /^.*(?=.{5})(?=.*\d)(?=.*\w).*$/g;
    return (value.match(regex) != null);
}

Now try this in the form by typing passwords such as “monster2” and “foo”. We have got both client-side validation and server-side validation of our custom rule!

Summary

In this post we have covered how to implement basic client-side and server-side validation using xVal, jQuery Validation and Data Annotation in ASP.NET MVC 2. We also went further and created remote validation and custom rules for both server-side and client-side. See the demo link below for a quick look how it turned out, and download the source for a closer look.

View the demo
Download the source

published in ASP.NET MVC, jQuery