DataAnnotations in ASP.NET MVC 1.0
DataAnnotations is the Microsoft way of declaratively adding validation rules to a model. You simply add an attribute to a property and voila, it has validation! The concept of DataAnnotations should be familiar to anyone who has worked in Ruby on Rails and added validation rules inside the ActiveRecord model. I'm going to go over some of my findings and walk you through using DataAnnotations. Hopefully my pain, will be your gain.
First of all, I want to say, DataAnnotations is one of the better concepts I've seen in terms of features for ASP.NET MVC. I'm a proponent of convention over configuration and moving the validation to the model, in a logical and simply way, is a positive step forward for the framework.
DataAnnotations replaces the myriad of techniques for performing validation, in a simple manner.
In the MVC tutorials, there is a simplified tutorial on DataAnnotations. I'm going to cover some of the same things as well as add a few tidbits...
--------------------------------------------------------
SETUP FOR MVC 1.0
- DataAnnotations is not currently supported by Microsoft. It is slated for release in the MVC 2.0 and .NET 4.0
- To install DataAnnotations you will need to download the Data Annotations Model Binder from the Microsoft CodePlex.
- Copy the Microsoft.Web.Mvc.DataAnnotations.dll and the System.ComponentModel.DataAnnotations.dll (different than the one in .NET 3.5 SP1) to your bin folder and add them as References to you project
- Finally, in Global.asax in the Appliction_Start add this line:
--------------------------------------------------------
USE WITH LINQ TO SQL
There is a fair amount of confusion when the DataAnnotations feature was announced surrounding its use when the Model is pre-generated, such as with Linq To SQL or Entity Framework. The confusion was from the use of the "buddy class" used to add the validation attributes.
A "buddy class" is necessary because partial properties, inside of partial classes, are not a function of the .NET. The reality is, the "buddy class" technique is very straightforward.
Below is an example of a class called Person and the associated "buddy class" that adds the validation attributes to it. Notice that we have one generated Linq To Sql class and a second class containing the validation rules.
using System.ComponentModel.DataAnnotations;
// This class is generated in Linq to Sql. This
// is the partial portion that allows me to add
// additional functionality to the Linq to Sql
// generated class.
//
// Note the addition of the MetadataType attribute.
// This attribute maps the values specified in the
// PersonMetadata class to those in my Linq to Sql Person class.
// This is how we get around the inability to have
// "partial properties".
[MetadataType(typeof(PersonMetadata))]
partial class Person
{
// Stuff goes here.
}
// This metadata class says that my Person
// is required to have a firstname and a lastname
public class PersonMetadata
{
[Required]
public object FirstName { get; set; }
[Required]
public object LastName { get; set; }
}
For a complete list of attributes that can be used
with DataAnnocations, check the DataAnnotations Namespace reference.
------------------------------------------------------
THE CONTROLLER
What I've already shown you has been covered in the tutorial. Because we've switched to a new, and unsupported, ModelBinder, I noticed a few issues and I'll get to those now.
The tutorial example shows that the Model is bound as a parameter of the Action, such as
public Create(Person person)
{
// check for validation errors
if(!ModelState.IsValid)
return View(person);
// we're ok, store in db
}
This is good if you're performing the binding in the parameter, however, I tend to use the UpdateModel or TryUpdateModel methods as I feel they can be used in more situations and provide greater flexibility.
However...using the UpdateModel method with our new model validation will result in validation errors throwing a InvalidOperationException. This is expected behavior but may trigger some unwanted changes in your controller code. The above code is adjusted to use UpdateModel instead of binding.
public Create()
{
var person = new Person();
try
{
UpdateModel<Person>(person);
}
catch(InvalidOperationException)
{
// we had a validation exception!
return View(person);
}
// we're ok, store in db
}
Alternatively, we can use the TryUpdateModel method. This has a similar quality to directly binding in the parameter and is the cleanest implementation in my opinion because it can be applied to almost every controller action.
public Create()
{
var person = new Person();
TryUpdateModel<Person>(person);
// check for validation errors
if(!ModelState.IsValid)
return View(person);
// we're ok, store in db
}
-------------------------------------------------------
THE VIEW
Now that everything else is in place, the view is fairly straight forward. Simply add a validation summary and validation messages to your view.
<% using (Html.BeginForm()) {%>
<fieldset>
<legend>Fields</legend>
<p>
<label for="FirstName">First Name:</label>
<%= Html.TextBox("FirstName") %>
<%= Html.ValidationMessage("FirstName", "*") %>
</p>
<p>
<label for="FirstName">Last Name:</label>
<%= Html.TextBox("LastName") %>
<%= Html.ValidationMessage("LastName", "*") %>
</p>
<p>
<input type="submit" value="Submit" />
</p>
<% } %>
<code>
Recent blog posts
- Canned VirtualPC Instances for IE 6, 7, 8 on XP/Vista
- Checking assembly dependencies for .NET
- Google's Public DNS
- Server Utility Functions for Non-Web Apps
- reCAPTCHA for ASP.NET MVC that uses ModelState
- Adding a container to ValidationSummary helper in ASP.NET MVC
- Generic XML Serialization Class
- Re-throwing Exceptions in C# with InternalPreserveStackTrace
- Solving xsd generation error: 'The element .... is missing'
- Enum DropDownList in ASP.NET MVC
Recent comments
5 weeks 4 days ago
5 weeks 6 days ago
12 weeks 4 days ago
41 weeks 6 days ago
43 weeks 29 min ago
46 weeks 2 days ago
48 weeks 15 hours ago
50 weeks 1 day ago
1 year 18 weeks ago
1 year 20 weeks ago