Click here to Skip to main content
16,015,296 members
Articles / Web Development / ASP.NET
Article

Creating Validation Engine for Domain Objects

Rate me:
Please Sign up or sign in to vote.
4.59/5 (11 votes)
15 Aug 2008CPOL3 min read 68.5K   402   45   13
In this article we will build a simple domain object validation framework using custom attributes and reflection.

Introduction

The brain of the application is represented by the domain. The domain consists of the business rules which make the application function properly. The rules must be validated in order to guarantee a successful operation. In this article we will build a simple domain object validation framework using custom attributes and reflection.

What does Domain Object Validation Means?

First we need to understand what domain objects validation means. Let’s consider a simple class Customer which is domain object. The Customer class consists of properties like FirstName, LastName etc. We need to make sure that the user does not leave FirstName and LastName empty. Of course, we can always use ASP.NET validation controls to make sure that the user inserts the fields but that validation is performed on the user interface level. We need to provide another layer of validation which validate the object based on the more complex business rules.

The Class Diagram

Take a look at the complete class diagram of the validation framework.

classdiagramvalidationframework_small.PNG

Now, let’s take a dive into the implementation.

Creating the Abstract ValidationAttribute Custom Attribute

The first task is to create custom attributes. To create an attribute your class must inherit from System.Attribute. Check out the implementation of the ValidationAttribute class below which serves as the abstract base class for all the validation attributes.

C#
public abstract class ValidationAttribute : System.Attribute
 {
     public string Message { get; set; }

     public abstract bool IsValid(object item);
 }

The ValidationAttribute class contains the properties and the methods that will be used and implemented by all the other validation classes.

Implementing the NotNullOrEmptyAttribute

Let’s implement the first validation attribute “NotNullOrEmptyAttribute.” This will make sure that the value of an object is not null or empty.

C#
[AttributeUsage(AttributeTargets.Property)]
    public class NotNullOrEmptyAttribute : ValidationAttribute
    {       

        public NotNullOrEmptyAttribute(string message)
        {
            Message = message;
        }
        
        public override bool IsValid(object item)
        {
            if (String.IsNullOrEmpty((string)item))
                return false;

            return true;             
        }
    }

As, you can see the implementation is quite simple! The IsValid method checks that if the value passed is valid or not. The good thing about using attribute based validation is that you can add more rules just by adding more custom attributes. The attribute can be decorated on the Customer class using the following syntax.

C#
public class Customer : BusinessBase
    {
        [NotNullOrEmpty("First name cannot be null or empty")]
        public string FirstName { get; set; }

        [NotNullOrEmpty("First name cannot be null or empty")]
        public string LastName { get; set; }
    }

Implementing the ValidationEngine

The ValidationEngine class is responsible for validating the business objects. Here is the complete implementation of the ValidationEngine.Validate<T> method.

C#
public static bool Validate<T>(T item) where T : BusinessBase
        {
            var properties = item.GetType().GetProperties(
                BindingFlags.Public | BindingFlags.Instance);

            foreach (var property in properties)
            {
                var customAtt = property.GetCustomAttributes(typeof(ValidationAttribute),
                    true);

                foreach (var att in customAtt)
                {
                    var valAtt = att as ValidationAttribute;
                    if (valAtt == null) continue;

                    if (valAtt.IsValid(property.GetValue(item, null))) continue;

                    var brokenRule = new BrokenRule
                                         {
                                             Message = String.Format("{0}:{1}",
                                             property.Name, valAtt.Message),
                                             PropertyName = property.Name
                                         };
                    item.BrokenRules.Add(brokenRule);
                }

            }

            return (item.BrokenRules.Count == 0);
        }

The Validate<T> method simply extracts all the properties from the object and check to see if it is decorated with the custom attribute of ValidationAttribute type. If it is then it invokes the IsValid method on the custom attribute class. If the object is not valid then the broken rules are added to the BrokenRules collection.

If you are more interested in validating your objects using the Customer.IsValid syntax then check out the following article which uses extension methods to add the extended functionality.

Desinging Application Using Test Driven Development Part 2

Using the ValidationEngine

ValidationEngine is pretty simple to use. Simply, pass in your object to the ValidationEngine.Validate<T> method and check to see if your object is valid or not based on the returned value. You also need to make sure that your object’s properties are decorated with correct validation attributes.

C#
static void Main(string[] args)
        {
            var customer = new Customer();

            ValidationEngine.Validate(customer);

            foreach(var brokenRule in customer.BrokenRules)
            {
                Console.WriteLine(brokenRule.Message);
            }
        }

Also, note that BrokenRules is a List<BrokenRule> collection which implements the IEnumerable interface. This means that you can easily bind your broken rules to a databound control like Repeater, ListView, DataList, DataGrid or GridView.

validationEngine_002.GIF

Conclusion

In this article we learned how to validate the business objects using custom attributes and reflection. You can extend the ValidationEngine class by providing more custom attributes each targeting a certain area of validation.

License

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


Written By
Web Developer
United States United States
My name is Mohammad Azam and I have been developing iOS applications since 2010. I have worked as a lead mobile developer for VALIC, AIG, Schlumberger, Baker Hughes, Blinds.com and The Home Depot. I have also published tons of my own apps to the App Store and even got featured by Apple for my app, Vegetable Tree. I highly recommend that you check out my portfolio. At present I am working as a lead instructor at DigitalCrafts.




I also have a lot of Udemy courses which you can check out at the following link:
Mohammad Azam Udemy Courses

Comments and Discussions

 
GeneralUse Case Pin
Chris Mulvey27-Apr-10 12:25
Chris Mulvey27-Apr-10 12:25 
GeneralRe: Use Case Pin
azamsharp27-Apr-10 14:19
azamsharp27-Apr-10 14:19 
GeneralGreat example Pin
hammerstein0520-Nov-09 7:18
hammerstein0520-Nov-09 7:18 
Generalsome thoughts Pin
DaProgramma18-Aug-08 21:18
DaProgramma18-Aug-08 21:18 
Hello,
your work is a simple example for iterating attributes, and it is OK so far.
But its no good idea to put validation logic into attributes. Some problems:

- cannot work with autogenerated code (e.g. with Entity Framework or any other ORM mapper)

- limited to single entity. How would you express for example, that if Name is given, Firstname must be given, too, but it would be OK to have both empty? You need a validation rule that covers Name and Firstname together.

Some more subtle things:

- cannot be used with standard databinding

- From a maintenance view, it would be much easier to have a static class, lets say "PersonValidater" with static methods that do the validations. Standard-Validation logic (like "cannot be empty") could be factored out to reusable helper functions.

Greetz
daProgramma
GeneralValidation Engine and Attributes Pin
liammclennan18-Aug-08 15:37
liammclennan18-Aug-08 15:37 
GeneralRe: Validation Engine and Attributes Pin
azamsharp18-Aug-08 16:09
azamsharp18-Aug-08 16:09 
GeneralRe: Validation Engine and Attributes Pin
ManishaPol18-Mar-10 2:00
ManishaPol18-Mar-10 2:00 
GeneralCSLA Pin
HoyaSaxa9316-Aug-08 3:40
HoyaSaxa9316-Aug-08 3:40 
GeneralRe: CSLA Pin
azamsharp16-Aug-08 4:19
azamsharp16-Aug-08 4:19 
QuestionWhy don't you use the Validation Application Block? Pin
King_kLAx15-Aug-08 22:41
King_kLAx15-Aug-08 22:41 
AnswerRe: Why don't you use the Validation Application Block? Pin
azamsharp16-Aug-08 4:17
azamsharp16-Aug-08 4:17 
GeneralGood one Pin
N a v a n e e t h15-Aug-08 17:58
N a v a n e e t h15-Aug-08 17:58 
GeneralRe: Good one Pin
azamsharp16-Aug-08 4:12
azamsharp16-Aug-08 4:12 

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.