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.
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:
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.
<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
.
<%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.