Introduction
In this article we will try to see how we can use DataAnnotations
to perform validations of
Model classes in an ASP.NET MVC application. We will see how using simple script includes will provide
us with the unobtrusive client side validations using the same DataAnnotations
attribute's logic.
Background
Whenever we are creating database driven applications. validations of user input is a very important aspect.
We need to validate all the data that is coming as user input to ensure that the data entered is valid and conforms
to the data type and length values of the respective field in the database.
In a MVC application, The business entities are represented as Model
classes. Now if we need to validate the
values of these model classes before pushing the data into the database we have two options. First option is that
we write all the client side scripts to validate the individual fields and also the server side code for validations
before putting the data into the Model. Now this server side is little problematic if we have strongly typed views
are strongly typed. It is not a good idea to validate all the fields' data individually.
The second option is more elegant and is very much supported by the MVC framework. This option is to
decorate the individual propertied with the DataAnnotation
attributes. Now using these attributes
we can specify various validation rules on individual fields of a Model class. This way we don't have to
write any extra validation code ourselves. Specifying these DataAnnotation
attributes will take care
of both server side and client side validations itself.
The DataAnnotation
attributes rely on the fact that whenever we try to add new record or update an existing record,
we will always check ModelState.IsValid
property. This will use the specified values in the attributes of the Model
and check for validation non conformance. In case the data is not valid, no action will be taken and the the user
will be presented with the problems in the data.
Let us now see how we can put simple DataAnnotation
attributes with a Model
class and it will Take care of
the client side and server side validations.
Using the code
Database and Validation Rules
Let is create a single table database. We will create a single table called as Contacts which will contain the
information of a contact person.
Now in this table, All the fields but ID are not-null
i.e. they will
be required from the user. Also, we have following length constraints on the individual fields.
-
FirstName
: varchar(50)
-
LastName
: varchar(50)
-
Address
: varchar(100)
-
PhoneNumber
: varchar(15)
-
eMail
: varchar(35)
So another validation rule for this table should be that the data coming from the user should not
exceed the maximum length of the individual fields. Another validation rule is that the phone
number should only be numeric and should not contain the
alphabets. And the email ID should be in the proper format.
So let us try to summarize the validation rules required for this table.
-
All the fields are required.
-
The length of user input should not exceed the length of respective fields.
-
PhoneNumber
should contain only numbers.
-
eMail
should be in the proper email format.
Now lets take these rules as the validation requirements for our application and start working on them.
Data Access
Now to perform data access we could use anything ranging from classic ADO.NET to ORMs like entity framework provided
that we model our data in terms of Model
classes. Let us use entity framework so that all the boilerplate
code for data access and data entities will be generated for us.
Once we have ADO.NET Entity Data Model added for this database we will have the following entity created
to be used as Model class in our application.
Creating the MVC application
Let us now add a simple controller that will provide the CRUD operations on this table/entity. Lets
use the scaffolds to generate the controller and views so that we can put our focus on data validations
only rather than creating controllers and view.
The Controller
code will now look like:
public class ContactController : Controller
{
private SampleDbEntities db = new SampleDbEntities();
public ViewResult Index()
{
return View(db.Contacts.ToList());
}
public ViewResult Details(int id)
{
Contact contact = db.Contacts.Single(c => c.ID == id);
return View(contact);
}
public ActionResult Create()
{
return View();
}
[HttpPost]
public ActionResult Create(Contact contact)
{
if (ModelState.IsValid)
{
db.Contacts.AddObject(contact);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(contact);
}
public ActionResult Edit(int id)
{
Contact contact = db.Contacts.Single(c => c.ID == id);
return View(contact);
}
[HttpPost]
public ActionResult Edit(Contact contact)
{
if (ModelState.IsValid)
{
db.Contacts.Attach(contact);
db.ObjectStateManager.ChangeObjectState(contact, EntityState.Modified);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(contact);
}
public ActionResult Delete(int id)
{
Contact contact = db.Contacts.Single(c => c.ID == id);
return View(contact);
}
[HttpPost, ActionName("Delete")]
public ActionResult DeleteConfirmed(int id)
{
Contact contact = db.Contacts.Single(c => c.ID == id);
db.Contacts.DeleteObject(contact);
db.SaveChanges();
return RedirectToAction("Index");
}
protected override void Dispose(bool disposing)
{
db.Dispose();
base.Dispose(disposing);
}
}
and the view created to perform the CRUD operations looks like
The Default Behavior
Now when we run the application we have the basic CRUD operations working for us. Now if we try to
create a new entry and put some invalid data the data will be submitted there are no validations in place.
Well not entirely true, entity framework is intelligent enough to detect the required fields and
validate against them. So if we try to submit without any values we will get some error message.
But these will be default messages generated by entity framework.
Now for the length, If we try to put the data that is of more length than an exception will be thrown.
Now we can simple avert this exception if we could validate the incoming data and check for the length.
And finally, for phone number and email format, there is no way they are getting validated. As long
as they are of valid length, they will simply be pushed into the database.
DataAnnotations
Now let us not depend on the default behavior and take control of the validation behavior in
our hand. We will do this by adding DataAnnotation
attributes in our Model
class. Since our model
class is auto generated will create a partial class with same name to add the data annotations on it.
[MetadataType(typeof(ContactMetaData))]
public partial class Contact
{
}
Now this class is adorned with the MetadataType
attribute which is present in DataAnnotations
namespace. This
indicated that the meta data for this Model class will be present in ContactMetaData
class. So this ContactMetaData
class will be the place to put in all our validation logic. Now this meta data class should contain same
public properties as that of the Model
class it is associated with.
Let us now take all the requirements one by one and try to put respective attributes with respective
properties of the Model class.
All field are required
Now this can be achieved by putting the Required
attribute with the properties as:
class ContactMetaData
{
[Required(ErrorMessage="First Name is required")]
public string FirstName { get; set; }
[Required(ErrorMessage = "Last Name is required")]
public string LastName { get; set; }
[Required(ErrorMessage = "Address is required")]
public string Address { get; set; }
[Required(ErrorMessage = "Phone Number is required")]
public string PhoneNumber { get; set; }
[Required(ErrorMessage = "eMail is required")]
public string eMail { get; set; }
}
The length of user input should not exceed the length of respective fields
Now this can be done by specifying the StringLength
attribute with all the properties.
class ContactMetaData
{
[Required(ErrorMessage="First Name is required")]
[StringLength(15, ErrorMessage = "First Name length Should be less than 50")]
public string FirstName { get; set; }
[Required(ErrorMessage = "Last Name is required")]
[StringLength(50, ErrorMessage = "Last Name length Should be less than 50")]
public string LastName { get; set; }
[Required(ErrorMessage = "Address is required")]
[StringLength(100, ErrorMessage = "Address length Should be less than 100")]
public string Address { get; set; }
[Required(ErrorMessage = "Phone Number is required")]
[StringLength(15, ErrorMessage = "Phone Number length Should be less than 15")]
public string PhoneNumber { get; set; }
[Required(ErrorMessage = "eMail is required")]
[StringLength(35, ErrorMessage = "eMail Length Should be less than 35")]
public string eMail { get; set; }
}
PhoneNumber and email Format
Now the next validation is for the phone number and email format. To do this
let us try to use regular expressions. All the input will be validated against a regular expression which
is specified as RegularExpression
attribute for the respective properties.
[RegularExpression(@"^[0-9]{0,15}$", ErrorMessage = "PhoneNumber should contain only numbers")]
public string PhoneNumber { get; set; }
[RegularExpression(@"^\w+@[a-zA-Z_]+?\.[a-zA-Z]{2,3}$", ErrorMessage = "eMail is not in proper format")]
public string eMail { get; set; }
Note: We have not seen the use of Range
attribute. It is used to specify range and its use is fairly
straight forward.
Client Side Unobtrusive Validations
Now these attributes will take care of server side validations. To use the same from client side we
need to include a couple of client side scripts and the same validation rules will work from client side
too(providing immediate feedback to the user).
<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>
Testing the application
Now we have the validation rules for our entity in place. Let us now try to see this in action. Lets try to submit the
form without putting any values.
Now lets try to put long data in some field and the number and email ID in wrong format.
But if all the data is valid the create operation will be successful with all the validations passed.
And thus by putting DataAnnotation
attributes in the Model's
metadata classes we have created both client side
and server side validation for our Model classes.
Point of interest
In this article we saw how we can use DataAnnotation
namespace to decorate the Model's
meta data classes and
perform server side and client side unobtrusive validations. This article has been written from a beginner's perspective.
I hope this has been informative.
History
-
15 April 2013: First version.