PrideParrot

The Blog

- Ramblings -

Search 

Introduction

In a web application the domain classes and the validations associated with those classes forms the Model. Validation plays a core part in a Model. In ASP.NET MVC, model validations are done by using Data Annotations. Data Annotations are nothing but special attributes that are applied over the properties of a class. If you have an Employee model then the validations are applied typically using Data Annotations as shown in the below listing,

public class Employee
{
    [Required]
    public string Name { get; set; }

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

Listing 1. Data Annotations

The Required validation attribute says that the corresponding property is mandatory for a model and the Email attribute specifies the value of the property should be a valid email. As you notice that you can stack more than one validation attribute over a property. In many cases these built-in validation attributes are not sufficient to fulfill our business requirements and in those cases we can go for building our own custom validations. ASP.NET MVC 3 provides different ways to build custom validations and in this article we are going to see about couple of ways, using ValidationAttribute and IValidatableObject interface.

A sample model

To learn about validations let's create a simple MVC application that helps anyone to host a super.. duper.. party!

Our application has only one model class Party.

public class Party
{
    public DateTime StartDate { get; set; }
      
    public int DurationInHours { get; set; }

    public int NoOfJoinees { get; set; }    

    public bool Drinks { get; set; }
}

Listing 2. Party model

The Party class contains only four properties and that's enough to demonstrate the validation stuff. Let's apply some simple basic validations to our model.

To apply validations using Data Annotations you should add a reference to the System.ComponentModel.DataAnnotations assembly.

Here are the basic rules that we are going to apply to our Party model.

1. The properties StartDate, DurationInHours and NoOfJoinees are required.
2. NoOfJoinees should not be more than 10 and not less than 2.

MVC provides a bunch of built-in validation attributes to suffice most of the validations we need. We already saw about the Required validation and that's what we should apply over the first three properties, for the NoOfJoinees property we should also apply the Range validation attribute along with the Required validation attribute. The Range validation attribute is used to restrict the value of a property between a minimum and a maximum value. In our example we have passed 2 as the minimum and 10 as the maximum values to the Range attribute's constructor.

After applying the basic validations our Party class looks as below,

public class Party
{
    [Required(ErrorMessage = "Start date is required")]
    public DateTime StartDate { get; set; }

    [Required(ErrorMessage = "Duration is required")]    
    public int DurationInHours { get; set; }

    [Required(ErrorMessage = "No. of joinees is required")]
    [Range(2, 10, ErrorMessage = "No. of joinees should be minimum 2 and not more than 10")]
    public int NoOfJoinees { get; set; }    

    public bool Drinks { get; set; }
}

Listing 3. Party model with basic validations

The System.ComponentModel.DataAnnotations assembly has many built-in validation attributes like Required, Range, RegularExpression and StringLength. All these attribute classes derives from the abstract class ValidationAttribute.

public abstract class ValidationAttribute : Attribute
{	
    public string ErrorMessage { get; set; }

    public virtual bool IsValid(object value);

    protected virtual ValidationResult IsValid(object value, ValidationContext 
    validationContext);

    // other members
}

Listing 4. Built-in abstract class ValidationAttribute

Create controller and view

Our Party model is ready with some basic validations applied, let's go and create a controller and a view to give a shot before going into creating custom validations. Create a single controller called PartyController with an action Index. The Index action returns a view that contains a form through which a user can fill the details of the party and submit to the application.

Controller

public class PartyController: Controller
{
    public ActionResult Index()
    {
        return View();
    }
}

Listing 5. PartyController

View

@model CustomValidation.MVC.Models.Party

@using (Html.BeginForm())
{
    @Html.ValidationSummary()
    

Start date (MM/dd/yyyy HH:mm:ss AM/PM) *: @Html.TextBoxFor(x => x.StartDate, new { size = 25 })

Duration (Hours) *: @Html.DropDownListFor(x => x.DurationInHours, new[]{ new SelectListItem(){ Text = "1", Value = "1"}, new SelectListItem(){ Text = "2", Value = "2"}, new SelectListItem(){ Text = "3", Value = "3"}, new SelectListItem(){ Text = "4", Value = "4"}, new SelectListItem(){ Text = "5", Value = "5"} }, "Select the duration", new { style = "width:180px" })

No. of joinees *: @Html.TextBoxFor(x => x.NoOfJoinees, new { size = 5 })

Drinks? @Html.CheckBoxFor(x => x.Drinks)

}

Listing 6. View

The @Html.ValidationSummary() method that used right below the form declaration in the view helps us to show all the validation errors of a model returned from the controller.

The view looks as below if you run the attached sample!

Index View

Index View

Let's create one more action in our controller that handles the POST request when the user submits the form.

[HttpPost]
public ActionResult Index(Party party)
{
    if(ModelState.IsValid)
    {
        // TO DO: save the party to database
        return View("Thanks");
    }
    return View();
}

Listing 7. Action that handles form POST

The Model Binding feature in ASP.NET MVC create and serve Model instances to the controller actions from the values available in QueryStrings, Form and other places of request.

Inside the action we are checking the POSTed party is valid and if yes then returning another view else returning the same view that will display the validation errors at the top of the form using the ValidationSummary() method that we saw earlier.

Our application is ready for a test drive! When we submit the form with wrong input values, the validation errors are displayed at the top of the form as shown in the below screen. We can even display the validation errors near to the input fields (that's what we do normally and for that we have to use @Html.ValidationMessageFor() in each field).

View with validation errors

View with validation errors

So far the validations we applied will happen only on the server side. In any web application it is common to do validations at both the client and server sides. Client-side validations provide great help in reducing server load as well as save the time of the user. Luckily, ASP.NET MVC framework helps to ease the client-side validations as well.

To enable client-side validation we have to do couple of things. First we have to make sure the ClientValidationEnabled and UnObtrusiveJavaScriptEnabled are set to true in web.config.

<appSettings>
    <add key="ClientValidationEnabled" value="true" />
    <add key="UnobtrusiveJavaScriptEnabled" value="true"/>
</appSettings>

Listing 8. Enabling client-side validation in configuration

The next thing is include the necessary javascript files in the layout page. We need to refer three javascript libraries.

1. jQuery
2. jQuery validation library
3. jQuery unobtrusive validation library (Developed by Microsoft)

<script src="@Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>

Listing 9. Referencing the required JS files for client-side validation

Once we have done these two things our validations are good to go at the client-side as well.

ValidationAttribute

We have seen how we can do basic validations quite easily. In some cases, we need to apply validations to class properties that are not supported by the built-in validation attributes. For example in our application we don't want any user to host a party for a past date. There are no built-in validation attributes supports this and so this is a good candidate for custom validation.

The ValidationAttribute approach is best suitable to implement validations that are reusable across classes.

We have already seen the abstract class ValidationAttribute in Listing 4, all the validation classes should derive from this class. For creating our custom validation attribute we are going to inherit from this class and implement the necessary methods. The ValidationAttribute class contains two overloaded IsValid methods. The first method takes an object value as an input parameter and returns a boolean. The second overloaded method takes couple of things; along with the object it takes another parameter of type ValidationContext.

Validation attributes can be applied to models as well, if the custom validation attribute is applied to a model then the complete model itself will be passed as value parameter to the IsValid methods. when the custom validation depends upon more than one property of a class then we can apply the attribute to the class or model itself.

Validation attributes are not only applied to properties but to classes as well.

In our scenario the StartDate should be a future date and it is independent of other properties so let's implement the first IsValid method. The implementation is quite simple as shown in the below listing.

public class FutureDateAttribute : ValidationAttribute
{
    public override bool IsValid(object value)
    {
		return value != null && (DateTime)value > DateTime.Now;
    }
}

Listing 10. FutureDateAttribute implementation

IClientValidatable

The custom validation we have applied to the Party model is done only at the server side and how we can do that in the client-side? The ASP.NET MVC team understands this problem and has come up with a solution for that. The solution is we have to implement an interface called IClientValidatable in our custom attribute class to enable client-side validation. The interface contains a single method named GetClientValidationRules that returns a collection of ModelClientValidationRule instances.

public class FutureDateValidatorAttribute : ValidationAttribute, IClientValidatable
{
    public override bool IsValid(object value)
    {
        return value != null && (DateTime)value > DateTime.Now;
    }

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
    {
        yield return new ModelClientValidationRule
        {         
            ErrorMessage = ErrorMessage,
            ValidationType = "futuredate"
        };
    }
}

Listing 11. Implementing IClientValidatable for client-side validation support

In the implementation we are just returning a single instance setting the error message and "futuredate" for the ValidationType. In ValidationType we can use any other name instead of "futuredate".

Implementing only this interface not completely solves the problem, we have to do couple of things more. We have to create a jQuery validator and adapter. In the validator we write the logic to evaluate the StartDate is a future date or not and in the adapter we set the error message that has to be displayed when validation fails.

jQuery.validator.addMethod('futuredate', function (value, element, params) {
    if (!/Invalid|NaN/.test(new Date(value))) {
        return new Date(value) > new Date();
    }
    return isNaN(value) && isNaN($(params).val()) || (parseFloat(value) > parseFloat($(params).val()));
}, '');

jQuery.validator.unobtrusive.adapters.add('futuredate', {}, function (options) {
    options.rules['futuredate'] = true;
    options.messages['futuredate'] = options.message;
});

Listing 12. jQuery validator and adapter

We have successfully created a custom validation by implementing the ValidationAttribute and IClientValidatable to perform the validation at both the client and server side.

IValidatableObject

The MVC framework provides another way to do custom validations using IValidatableObject. Unlike the ValidationAttribute the IValidatableObject is implemented in the model class itself. The IValidatableObject contains a single method called Validate that returns a collection of ValidationResult instances.

public interface IValidatableObject
{    
    IEnumerable<ValidationResult> Validate(ValidationContext validationContext);
}

Listing 13. IValidatableObject

The important differences between the ValidationAttribute and IValidatableObject are: the former one is used to perform a single validation while the later one is used to perform single or multiple validations. If we want the validation to happen both at the server-side and at the client-side then the ValidationAttribute is the right choice. If we want the validations should happen only at the server-side then IValidatableObject is the right choice. The IClientValidatable only supports ValidationAttribute for client-side validations and not IValidatableObject.

ValidationAttribute is used to perform a single validation. IValidatableObject can be used to do multiple validations.

We are going to add two more validations to our Party class. The party provider doesn't allow the party to continue after 10 PM (bad!) and they don't server drinks if the NoOfJoinees is less than 5 (too bad!). If you see these validations they are pretty much tied to the business and they can't be reusable across classes, so the best way to go is IValidatableObject approach. The other thing is we can do a set of validations using this approach.

Here is the implementation,

public class Party : IValidatableObject
{
    [Required(ErrorMessage = "Start date is required")]
    [FutureDateValidator(ErrorMessage = "Start date should be a future date")]
    public DateTime StartDate { get; set; }

    [Required(ErrorMessage = "Duration is required")]    
    public int DurationInHours { get; set; }

    [Required(ErrorMessage = "No. of joinees is required")]
    [Range(2, 10, ErrorMessage = "No. of joinees should be minimum 2 and not more than 10")]
    public int NoOfJoinees { get; set; }    

    public bool Drinks { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        if (StartDate.TimeOfDay > new TimeSpan(22 - DurationInHours, 0, 0))
        {
            yield return new ValidationResult("The party should not exceed after 10.00 PM");
        }
        
        if (NoOfJoinees < 5 && Drinks)
        {
            yield return new ValidationResult("Drinks are only allowed if no. of joinees is 5 or more.");
        }
    }
}

Listing 14. Implementing IValidatableObject in Party class

Summary

In this article we saw how to do model validations in ASP.NET MVC 3. At start we saw how to do some basic validations using the built-in validation attributes, then we looked into enabling client-side validation using the IClientValidatable interface.

ASP.NET MVC provides different approaches to implement custom validations and we saw two. The first approach is by implementing the ValidationAttribute abstract class, this is best suitable when we want to do a single validation both at the server and client sides. The next approach is by using the IValidatableObject interface, this is best suitable when we want to do two or more validations only in the server-side.

Download

← Back to Homepage
blog comments powered by Disqus
Subscribe