Wednesday, October 12, 2011

Validation with the Data Annotation Validators

In this tutorial, you learn how to use the Data Annotation validators to perform validation in an ASP.NET MVC application. 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.
Before you can use the Data Annotation validators, you must download the Data Annotations Model Binder. You can download the Data Annotations Model Binder Sample from the CodePlex website by clicking here.
It is important to understand that the Data Annotations Model Binder is not an official part of the Microsoft ASP.NET MVC framework. Although the Data Annotations Model Binder was created by the Microsoft ASP.NET MVC team, Microsoft does not offer official product support for the Data Annotations Model Binder described and used in this tutorial.

Using the Data Annotation Model Binder

In order to use the Data Annotations Model Binder in an ASP.NET MVC application, you first need to add a reference to the Microsoft.Web.Mvc.DataAnnotations.dll assembly and the System.ComponentModel.DataAnnotations.dll assembly. Select the menu option Project, Add Reference. Next click the Browse tab and browse to the location where you downloaded (and unzipped) the Data Annotations Model Binder sample (see Figure 1).
Figure 1: Adding a reference to the Data Annotations Model Binder (Click to view full-size image)
Select both the Microsoft.Web.Mvc.DataAnnotations.dll assembly and the System.ComponentModel.DataAnnotations.dll assembly and click the OK button.
You cannot use the System.ComponentModel.DataAnnotations.dll assembly included with .NET Framework Service Pack 1 with the Data Annotations Model Binder. You must use the version of the System.ComponentModel.DataAnnotations.dll assembly included with the Data Annotations Model Binder Sample download.
Finally, you need to register the DataAnnotations Model Binder in the Global.asax file. Add the following line of code to the Application_Start() event handler so that the Application_Start() method looks like this:
protected void Application_Start()
{
RegisterRoutes(RouteTable.Routes);
ModelBinders.Binders.DefaultBinder = new Microsoft.Web.Mvc.DataAnnotations.DataAnnotationsModelBinder();
}

This line of code registers the ataAnnotationsModelBinder as the default model binder for the entire ASP.NET MVC application.

Using the Data Annotation Validator Attributes

When you use the Data Annotations Model Binder, you use validator attributes to perform validation. The System.ComponentModel.DataAnnotations namespace includes the following validator attributes:
  • Range – Enables you to validate whether the value of a property falls between a specified range of values.
  • ReqularExpression – Enables you to validate whether the value of a property matches a specified regular expression pattern.
  • Required – Enables you to mark a property as required.
  • StringLength – Enables you to specify a maximum length for a string property.
  • Validation – The base class for all validator attributes.
If your validation needs are not satisfied by any of the standard validators then you always have the option of creating a custom validator attribute by inheriting a new validator attribute from the base Validation attribute.
The Product class in Listing 1 illustrates how to use these validator attributes. The Name, Description, and UnitPrice properties are marked as required. The Name property must have a string length that is less than 10 characters. Finally, the UnitPrice property must match a regular expression pattern that represents a currency amount.
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;

namespace MvcApplication1.Models
{

public class Product
{
public int Id { get; set; }

[Required]
[StringLength(10)]
public string Name { get; set; }

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

[DisplayName("Price")]
[Required]
[RegularExpression(@"^\$?\d+(\.(\d{2}))?$")]
public decimal UnitPrice { get; set; }
}
}

Listing 1: Models\Product.cs
The Product class illustrates how to use one additional attribute: the DisplayName attribute. The DisplayName attribute enables you to modify the name of the property when the property is displayed in an error message. Instead of displaying the error message “The UnitPrice field is required” you can display the error message “The Price field is required”.
If you want to completely customize the error message displayed by a validator then you can assign a custom error message to the validator’s ErrorMessage property like this: <Required(ErrorMessage:=”This field needs a value!”)>
You can use the Product class in Listing 1 with the Create() controller action in Listing 2. This controller action redisplays the Create view when model state contains any errors.
using System.Web.Mvc;
using MvcApplication1.Models;

namespace MvcApplication1.Controllers
{
public class ProductController : Controller
{
//
// GET: /Product/Create

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

//
// POST: /Product/Create

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create([Bind(Exclude="Id")]Product productToCreate)
{
if (!ModelState.IsValid)
return View();

// TODO: Add insert logic here
return RedirectToAction("Index");
}


}
}

Listing 2: Controllers\ProductController.vb
Finally, you can create the view in Listing 3 by right-clicking the Create() action and selecting the menu option Add View. Create a strongly-typed view with the Product class as the model class. Select Create from the view content dropdown list (see Figure 2).
Figure 2: Adding the Create View
<%@ Page Title="" Language="C#" MasterPageFile="Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<MvcApplication1.Models.Product>" %>

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">

<h2>Create</h2>

<%= Html.ValidationSummary("Create was unsuccessful. Please correct the errors and try again.") %>

<% using (Html.BeginForm()) {%>

<fieldset>
<legend>Fields</legend>
<p>
<label for="Name">Name:</label>
<%= Html.TextBox("Name") %>
<%= Html.ValidationMessage("Name", "*") %>
</p>
<p>
<label for="Description">Description:</label>
<%= Html.TextBox("Description") %>
<%= Html.ValidationMessage("Description", "*") %>
</p>
<p>
<label for="UnitPrice">Price:</label>
<%= Html.TextBox("UnitPrice") %>
<%= Html.ValidationMessage("UnitPrice", "*") %>
</p>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>

<% } %>

<div>
<%=Html.ActionLink("Back to List", "Index") %>
</div>

</asp:Content>







Listing 3: Views\Product\Create.aspx
Remove the Id field from the Create form generated by the Add View menu option. Because the Id field corresponds to an Identity column, you don’t want to allow users to enter a value for this field.
If you submit the form for creating a Product and you do not enter values for the required fields, then the validation error messages in Figure 3 are displayed.
Figure 3: Missing required fields
If you enter an invalid currency amount, then the error message in Figure 4 is displayed.
Figure 4: Invalid currency amount

Using Data Annotation Validators with the Entity Framework

If you are using the Microsoft Entity Framework to generate your data model classes then you cannot apply the validator attributes directly to your classes. Because the Entity Framework Designer generates the model classes, any changes you make to the model classes will be overwritten the next time you make any changes in the Designer.
If you want to use the validators with the classes generated by the Entity Framework then you need to create meta data classes. You apply the validators to the meta data class instead of applying the validators to the actual class.
For example, imagine that you have created a Movie class using the Entity Framework (see Figure 5). Imagine, furthermore, that you want to make the Movie Title and Director properties required properties. In that case, you can create the partial class and meta data class in Listing 4.
Figure 5: Movie class generated by Entity Framework
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;

namespace MvcApplication1.Models
{
[MetadataType(typeof(MovieMetaData))]
public partial class Movie
{
}


public class MovieMetaData
{
[Required]
public object Title { get; set; }

[Required]
[StringLength(5)]
public object Director { get; set; }


[DisplayName("Date Released")]
[Required]
public object DateReleased { get; set; }
}

}
Listing 4: Models\Movie.cs
The file in Listing 4 contains two classes named Movie and MovieMetaData. The Movie class is a partial class. It corresponds to the partial class generated by the Entity Framework that is contained in the DataModel.Designer.vb file.
Currently, the .NET framework does not support partial properties. Therefore, there is no way to apply the validator attributes to the properties of the Movie class defined in the DataModel.Designer.vb file by applying the validator attributes to the properties of the Movie class defined in the file in Listing 4.
Notice that the Movie partial class is decorated with a MetadataType attribute that points at the MovieMetaData class. The MovieMetaData class contains proxy properties for the properties of the Movie class.
The validator attributes are applied to the properties of the MovieMetaData class. The Title, Director, and DateReleased properties are all marked as required properties. The Director property must be assigned a string that contains less than 5 characters. Finally, the DisplayName attribute is applied to the DateReleased property to display an error message like “The Date Released field is required.” instead of the error “The DateReleased field is required.”
Notice that the proxy properties in the MovieMetaData class do not need to represent the same types as the corresponding properties in the Movie class. For example, the Director property is a string property in the Movie class and an object property in the MovieMetaData class.
The page in Figure 6 illustrates the error messages returned when you enter invalid values for the Movie properties.
Figure 6: Using validators with the Entity Framework (Click to view full-size image)

Summary

In this tutorial, you learned how to take advantage of the Data Annotation Model Binder to perform validation within an ASP.NET MVC application. You learned how to use the different types of validator attributes such as the Required and StringLength attributes. You also learned how to use these attributes when working with the Microsoft Entity Framework.