Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#4.0

Model level validation using ASP.NET MVC

4.13/5 (6 votes)
18 Feb 2010CPOL3 min read 27.7K  
The benefit of putting validation in the model layer is that, the validation rules will be enforced everywhere in the application that accesses the database. It also means that we can change the validation rule in one place and every UI element inside our app will automatically get updated.

Introduction

When building your MVC application, you want to use your application controller to basically handle the input and the application user interface (views). You don't want to embed business logic inside your controllers. The best thing to do is to create a service layer which is basically a layer between the controller and the data layer. When it comes to validation, for xample, I want to make sure that the unit price is greater than zero, or let's say, the product name is never empty, I don't want to write code inside my controller or inside my views. For that, I want to put my logic inside my business layer, that is the model layer. The benefit of putting this validation in model layer is that the validation rule will be enforced anywhere in the application that accesses the database. It also means that we can change the validation rule in one place and every UI element inside our app will automatically get updated to a data manager. For the Add, Edit, Delete scenario, if we are able to add validation in the model layer, all of those different actions rules enforce the validation rule before updating the database.

In ASP.NET MVC, there are multiple ways for doing model level validation. You can write your own validation logic inside the business layer. In ASP.NET MVC version 1, we had support for IDataErrorInfo which is the standard interface WPF and Windows Forms support. In ASP.NET MVC 2, we have another built-in mechanism which uses the data annotation feature, dynamic data used inside ASP.NET web forms. Silverlight also uses this capability inside RIA services.

IDataErrorInfo Sample

The following code uses the IDataErrorInfo interface to generate validation error messages. Create a partial Question class that extends the functionality of the partial Question class generated by the Entity Framework. Next, we add validation logic to the Question class OnTitleChanging() partial methods. Finally, implement the IDataErrorInfo interface in order to expose these validation messages to the ASP.NET MVC framework.

C#
using System.Collections.Generic;
using System.ComponentModel;
namespace MvcApplication1.Models
{
    public partial class Question : IDataErrorInfo
    {
        private Dictionary<string,> _errors = 
                new Dictionary<string,>();
        partial void OnTitleChanging(string value)
        {
            if (value.Trim().Length > 20)
                _errors.Add("Title", 
                "Title should not be more than 20 characters.");
        }
        #region IDataErrorInfo Members
        public string Error
        {
            get
            {
                return string.Empty;
            }
        }

        public string this[string columnName]
        {
            get
            {
                if (_errors.ContainsKey(columnName))
                    return _errors[columnName];
                return string.Empty;
            }
        }
        #endregion
    }
}

The ASP.NET MVC framework creates the instance of Question passed to the Create() action by using a model binder (the DefaultModelBinder). The model binder is responsible for creating an instance of the Question object by binding the HTML form fields to an instance of the Movie object. The DefaultModelBinder detects whether or not a class implements the IDataErrorInfo interface. If a class implements this interface, then the model binder invokes the IDataErrorInfo.this indexer for each property of the class. If the indexer returns an error message, then the model binder adds this error message to the model state automatically.

Data Annotation Validators

The advantage of using the Data Annotation validators is that they enable you to perform validation simply by adding one or more attributes, such as the Required or StringLength attribute, to a class property.

C# and VB.NET do not support partial properties. There is a concept called buddy classes, where we can add our validation rules there and link them to the actual model. The following example shows an implementation:

C#
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;

namespace MvcApplication1.Models
{
    [MetadataType(typeof(Question_Validate))]
    public partial class Question
    {
    }


    public class Question_Validate
    {
        [StringLength(20, "Title should not be more than 20 characters.")]
        public object Title { get; set; }

    }
}

Notice that the Question partial class is decorated with a MetadataType attribute that points to the Question_Validate class. The Question_Validate class contains proxy properties for the properties of the Question class.

Client-side Validation

By default, the above sample will work on the server, but to get this working with the client validation, we need just two steps. The first step is to reference the appropriate scripts.

XML
<script src="../../Scripts/jquery-1.3.2.min.js" type="text/javascript"/>
<script src="../../Scripts/jquery.validate.min.js" type="text/javascript"/>
<script src="../../Scripts/MicrosoftAjax.js" type="text/javascript"/>
<script src="../../Scripts/MicrosoftMvcValidation.js" type="text/javascript"/>

The next step is to enable client validation for the form by calling EnableClientValidation before we call BeginForm.

XML
<%Html.EnableClientValidation(); %>

Summary

We have seen how we can implement the IDataErrorInfo interface and also take advantage of the Data Annotation Model Binder to perform validation within an ASP.NET MVC application.

License

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