Click here to Skip to main content
15,867,756 members
Articles / Programming Languages / C# 4.0

DataAnnotations Validation for Beginner

Rate me:
Please Sign up or sign in to vote.
4.96/5 (23 votes)
17 Sep 2011CPOL4 min read 154.3K   2.9K   54   9
In this article, I will explain how to use DataAnnotations library's validation feature for domain entity with a simple demo application.

Introduction

When you have domain entities in domain layer, usually you also have validation rules as a part of entities’ business rules. You will face the question where to specify the validation rules and how to verify the validation rules. This article will show you a way by using DataAnnotations library to specify and verify validation rules for domain entities.

Domain Entity

A domain entity is a class used to represent something in your problem domain. A typical domain entity looks like this:

C#
public class Customer
{
	public virtual string CustomerID { get; set; }
	public virtual string CompanyName { get; set; }
	public virtual string Address { get; set; }
	public virtual string City { get; set; }
	public virtual string PostalCode { get; set; }
	public virtual string Country { get; set; }
	public virtual string Phone { get; set; }
}

This domain entity is used to represent Customer in system by holding Customer related information. I assume when adding a new customer into the system, you must provide CustomerID and CompanyName, and the CompanyName must have maximum 10 characters. If you provided value for Country, then the value must be USA. If you provided value for Phone, then the phone number must have correct format. In summary, the Customer entity has following validation rules:

  1. CustomerID is required
  2. CompanyName is required
  3. CompanyName can have maximum 10 characters
  4. Country can only be USA when there is a value
  5. Phone must have format ###-###-#### (# means digit) when there is a value

DataAnnotations

DataAnnotations is a library in .NET Framework. It resides in assembly System.ComponentModel.DataAnnotations. The purpose of DataAnnotations is to custom domain entity class with attributes. Therefore, DataAnnotations contains validation attributes to enforce validation rules, display attributes to specify how data from the class or member is displayed, and data modeling attributes to specify the intended use of data members and the relationships between data classes. One example of validation attribute is RequiredAttribute that is used to specify that a value must be provided. One example of display attribute is DisplayAttribute that is used to specify localizable strings for data types and members that are used in the user interface. And, one example of data modeling attribute is KeyAttribute that is used to specify the property as unique identity for the entity. We will only show how to use validation attributes in here to verify validation rules for domain entity.

Specify Validation Rule for Domain Entity

Before we can verify validation rules of Customer entity, we need to put two built-in validation attributes of DataAnnotations, RequiredAttribute and StringLengthAttribute, on Customer class. The Customer class will be something like this:

C#
public class Customer
{
	[Required]
	public virtual string CustomerID { get; set; }

	[Required]
	[StringLength(15)]
	public virtual string CompanyName { get; set; }

	public virtual string Address { get; set; }

	public virtual string City { get; set; }

	public virtual string PostalCode { get; set; }

	public virtual string Country { get; set; }

	public virtual string Phone { get; set; }
}

Let’s take a look at RequiredAttribute and StringLengthAttribute in detail:

ValidationAttributes.gif

RequiredAttribute and StringLengthAttribute all inherit from ValidationAttribute that is the base class of all validation attributes.
With the use of RequiredAttribute and StringLengthAttribute, we are only able to specify validation rules for the first three requirements, how about the last two requirements: Country can only be USA when there is a value and Phone must have format ###-###-#### (# means digit) when there is a value. The solution is to create custom validation attributes for them. We need to create two custom validation attributes here, one is for Country and another one is for Phone.

CountryAttribute for Country Validation

C#
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, 
	AllowMultiple = false, Inherited = true)]
public class CountryAttribute: ValidationAttribute
{
	public string AllowCountry { get; set; }

	public override bool IsValid(object value)
	{
		if (value == null)
		{
			return true;
		}

		if (value.ToString() != AllowCountry)
		{
			return false;
		}

		return true;
	}
}

PhoneAttribute for Phone Validation

C#
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, 
	AllowMultiple = false, Inherited = true)]
public class PhoneAttribute : RegexAttribute
{
	public PhoneAttribute()
		: base(@"^[2-9]\d{2}-\d{3}-\d{4}$", RegexOptions.IgnoreCase)
	{ }
}

The class diagram is like this:

CustomValidationAttributes.gif

At the end, Customer class with all validation attributes on it will be like this:

C#
public class Customer
{
	[Required]
	public virtual string CustomerID { get; set; }

	[Required]
	[StringLength(15)]
	public virtual string CompanyName { get; set; }

	public virtual string Address { get; set; }

	public virtual string City { get; set; }

	public virtual string PostalCode { get; set; }

	[Country(AllowCountry="USA")]
	public virtual string Country { get; set; }

	[Phone]
	public virtual string Phone { get; set; }
}

Verify Validation Rules for Domain Entity

After validation rules are specified on Customer entity, we can verify Customer against the rules in our application with DataAnnotations.Validator class.

C#
[TestMethod]
public void ValidateCustomer_Customer_NoError()
{
	// Arrange
	Customer customer = new Customer();
	customer.CustomerID = "aaa";
	customer.CompanyName = "AAA company";

	// Act
	var validationResult = ValidationHelper.ValidateEntity<customer>(customer);

	// Assert
	Assert.IsFalse(validationResult.HasError);
}

ValidationHelper is a helper class that wraps up the call to DataAnnotations.Validator.

C#
public class EntityValidationResult
{
	public IList<validationresult> Errors { get; private set; }
	public bool HasError
	{
		get { return Errors.Count > 0; }
	}

	public EntityValidationResult(IList<validationresult> errors = null)
	{
		Errors = errors ?? new List<validationresult>();
	}
}

public class EntityValidator<t> where T : class
{
	public EntityValidationResult Validate(T entity)
	{
		var validationResults = new List<validationresult>();
		var vc = new ValidationContext(entity, null, null);
		var isValid = Validator.TryValidateObject
				(entity, vc, validationResults, true);

		return new EntityValidationResult(validationResults);
	}
}

public class ValidationHelper
{
	public static EntityValidationResult ValidateEntity<t>(T entity)
		where T : class
	{
		return new EntityValidator<t>().Validate(entity);
	}
}

The line of code that does actual validation is:

C#
var isValid = Validator.TryValidateObject(entity, vc, validationResults, true);

Note: The last parameter, validateAllProperties, of TryValidateObject method is a Boolean type variable. You must pass in true to enable verification on all types of validation attributes, include the custom validation attributes we used above. If you pass in false, only RequiredAttribute used on entity will be verified. The name of this parameter is very misleading.

The validation process is like this:

ValidationSequence.gif

Summary

DataAnnotations library provides an easy way to specify and verify validation rules on domain entity. Also, it is opening for change by design, so developers can add their own validation attributes for their own situation. By specifying validation rules on domain entity directly allow upper layers have no worry of validation anymore.

Using the Code

The code is developed in Visual Studio 2010.

History

  • 17th September, 2011: Initial post

License

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


Written By
Software Developer (Senior)
United States United States
Senior Software Developer from New Jersey, USA

Have 15+ years experience on enterprise application development with various technologies.

Comments and Discussions

 
QuestionHow can I tell the Data Annotations validator to also validate complex child properties Pin
FrancisTamil selvan29-Jun-16 0:52
FrancisTamil selvan29-Jun-16 0:52 
GeneralMy Vote is 5 Pin
californiacoder25-Nov-15 21:37
californiacoder25-Nov-15 21:37 
QuestionQuestion Pin
Saeed Mirzaee9-Nov-14 23:52
Saeed Mirzaee9-Nov-14 23:52 
AnswerRe: Question Pin
Henry He10-Nov-14 4:07
Henry He10-Nov-14 4:07 
The ?? operator is a C# syntax sugar.
C#
Erros = errors ?? new List();

Equals to
C#
Errors = errors != null ? errors : new List();


Please check MSDN http://msdn.microsoft.com/en-us/library/ms173224.aspx[^]
QuestionHow can use DataAnnotaions in webforms? Pin
M.Hussain.22-May-13 4:19
M.Hussain.22-May-13 4:19 
AnswerRe: How can use DataAnnotaions in webforms? Pin
Henry He22-May-13 16:21
Henry He22-May-13 16:21 
GeneralMy vote of 5 Pin
SleepyCrat7-Feb-13 12:28
SleepyCrat7-Feb-13 12:28 
GeneralThanks Pin
morzel29-Dec-12 6:32
morzel29-Dec-12 6:32 
GeneralMy vote of 5 Pin
Dan Mordechay10-Jul-12 20:38
Dan Mordechay10-Jul-12 20:38 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.