Click here to Skip to main content
Click here to Skip to main content

Model Validation in ASP.NET MVC

By , 15 Apr 2014
Rate this:
Please Sign up or sign in to vote.

"THE ARTICLE IS NO LONGER MAINTAINED HERE. PLEASE POST ANY FURTHER DISCUSSIONS/QUESTIONS IN MY BLOG http://www.prideparrot.com/blog/archive/2012/4/model_validation_in_asp_net_mvc" - Author

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 to a class or properties of a class. If you have an Employee class 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 specifies that the corresponding property is mandatory for the model and the Email attribute specifies that 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 some 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.

In this article we will see how to apply basic validations to a model and also we will see how to create custom validations by implementing the ValidationAttribute class or IValidatableObject interface.

A sample model

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

Our sample application has only one model class called 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
To apply validations using Data Annotations you should add a reference to the System.ComponentModel.DataAnnotations assembly.

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 3. Built-in abstract class ValidationAttribute

Let's apply some simple basic validations to our model. 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. We already saw about the Required validation attribute 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.

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 4. Party model with basic validations

Create controller and view

Our Party model is ready with some basic validations applied, let's go and create a controller and a view for the model. Create a single controller called PartyController having a single action Index. The Index action returns a view that contains a form through which a user can fill and submit the details of the party.

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)

        <input type="submit" value="Host the party!" />
}
Listing 6. View

The @Html.ValidationSummary() method that we 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's POST
The Model Binding feature in ASP.NET MVC create and serve model instances to the controller actions from the values available in QueryStrings and form.

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.

Our application is ready for a test drive!

When you 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).

View with validation errors

View with validation errors

So far the validations we applied will happen only at 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 saves the time of the user. Luckily, ASP.NET MVC framework helps to ease the client-side validations.

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.

<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 ASP.NET MVC. 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 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)
    {      
<pre lang="cs" id="pre10" style="white-space: pre-wrap; word-wrap: break-word; margin-removed 0px; ">      return value != null && (DateTime)value > DateTime.Now; 
} }
Listing 10. Custom validation attribute

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 also? 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. We can use any other name instead of "futuredate" for ValidationType.

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 the 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.

Below listing shows 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. 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.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

After2050
Software Developer Trigent Software Private Limited
India India
I'm a software developer from south tip of India. I spent most of the time in learning new technologies. I've a keen interest in client-side technologies especially JavaScript and admire it is the most beautiful language ever seen.
 
I like sharing my knowledge and written some non-popular articles. I believe in quality and standards but blames myself for lagging them.
 
I believe in small things and they makes me happy!
Follow on   Twitter

Comments and Discussions

 
GeneralMy vote of 5 PinmemberTridip Bhattacharjee24-Sep-12 20:20 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web03 | 2.8.140421.2 | Last Updated 15 Apr 2014
Article Copyright 2012 by After2050
Everything else Copyright © CodeProject, 1999-2014
Terms of Use
Layout: fixed | fluid