KoffeeKoder


  • Creating the Validation Framework
    published on 6/10/2008 7:48:22 PM
  • Validation is an important part of any application. This must be implemented with extreme care. We cannot only rely on the UI validation. The domain objects must also be validated at the business layer level. There are various ways of introducing validation support for domain objects at the business layer. I like the attribute based validation since it is a clean approach and when implemented in a separated assembly it can be reused.

    There are different ways of implementing the validation rules using attributes. This technique is by creating a separate class to perform validation. The class is called ValidationEngine and its sole purpose is to validate the object. Let’s take a look at the ValidationEngine class.

    public class ValidationEngine
        {
            private List<ValidationRule> _brokenRules = new List<ValidationRule>();

            public void Validate<T>(T item)
            {
                PropertyInfo[] properties = item.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
                foreach (PropertyInfo property in properties)
                {
                    object[] customAtt = property.GetCustomAttributes(typeof(ValidationAttribute), true);

                    foreach (object att in customAtt)
                    {
                        ValidationAttribute valAtt = att as ValidationAttribute;
                        if (valAtt != null)
                        {
                            if (!valAtt.IsValid(property.GetValue(item, null)))
                            {
                                (BrokenRules as List<ValidationRule>).Add(new ValidationRule(property.Name,valAtt.Message));                     
                            }
                        }
                    }

                }
                
            }

            public List<ValidationRule> BrokenRules
            {
                get { return _brokenRules; }
                set { _brokenRules = value; }
            }

        }

    The Validate<T> method takes in the object and uses reflection to read the custom attributes and perform validation. Usually, it is a good idea to keep the validation logic and implementation in a separate assembly so that it can be reused in different projects. The BrokenRules property returns the list of BrokenRules for the object. The BrokenRule list is of type ValidationRule which consist of a PropertyName and the Message. The ValidationRule class is implemented as follows:

    public class ValidationRule
        {
            public string PropertyName { get; set; }
            public string Message { get; set; }

            public ValidationRule()
            {

            }

            public ValidationRule(string propertyName,string message)
            {
                PropertyName = propertyName;
                Message = message;
            }

        }

    Now, let’s take a look at the ValidationAttribute class which serves as the Base class for all the validation classes.

    public abstract class ValidationAttribute : System.Attribute
        {
            private string _message;

            public abstract bool IsValid(object item);

            public string Message
            {
                get { return _message; }
                set { _message = value; }
            }
        }

    Now, let’s take a look at the concrete classes. The first class is NotNullOrEmpty attribute which makes sure that the value of not null or empty.

    [AttributeUsage(AttributeTargets.Property)]
        public class NotNullOrEmpty : ValidationAttribute
        {       
            public NotNullOrEmpty(string message)
            {
                Message = message;
            }

            public override bool IsValid(object item)
            {
                if (String.IsNullOrEmpty(item as String))
                    return false;

                return true;
            }
        }

    And here is the attribute in action.

    public class Customer
        {
           
            private string _name;
            private string _title;
            private string _phone;

            [NotNullOrEmpty("name cannot be null or empty")]
            public string Name
            {
                get { return _name; }
                set { _name = value; }
            }

            [NotNullOrEmpty("title cannot be null or empty")]
            public string Title
            {
                get { return _title; }
                set { _title = value; }
            }

    As, you can see from the above code the NotNullOrEmpty is decorated on the Name and Title property this will make sure that the property is not null or empty.


    Let’s test out our new validation framework.

    [RowTest]
            [Row("","Senior Consultant","2343332123")]
            public void should_get_property_name_within_broken_rules_if_customer_name_is_empty(
                string name, string title, string phone)
            {
                Customer customer = new Customer() { Name = name, Phone = phone, Title = title };
                validationEngine.Validate<Customer>(customer);

                Assert.AreEqual("Name", validationEngine.BrokenRules[0].PropertyName);
            }

    You don’t need to test the attribute for each and every property. This is because you are not testing the property name but you are testing the workings of the attribute. The context in your test is the validation attribute and not the object’s property.

    The great thing about this way of validation is that now you can easily extend your validation by simply creating more custom attributes. Take a look at the RegexExpression attribute which validates the value based on the regular expression.

    public class RegexExpression : ValidationAttribute
        {
            private string _expression;

            public RegexExpression(string expression, string message)
            {
                _expression = expression;
                Message = message;
            }

            public override bool IsValid(object item)
            {
                Regex reg = new Regex(_expression);

                if (!reg.IsMatch(item as String))
                    return false;

                return true;
                
            }
        }

    And here is the usage:

    [NotNullOrEmpty("phone cannot be null or empty")]
            [RegexExpression(@"^\D?(\d{3})\D?\D?(\d{3})\D?(\d{4})$", "phone number is in incorrect format")]
            public string Phone
            {
                get { return _phone; }
                set { _phone = value; }
            }

    Here is the unit test for the RegexExpression for the phone format:

      [RowTest]
            [Row("john","Senior Consultant","123")]
            [Row("john","Senior Consultant","123432345")]
            [Row("john","Senior Consultant","123-232-21234")]        
            public void should_get_a_broken_rule_if_phone_number_is_not_in_correct_format(string name, string title,string phone)
            {
                Customer customer = new Customer() { Name = name, Title = title, Phone = phone };
                validationEngine.Validate<Customer>(customer);

                Assert.AreEqual(1, validationEngine.BrokenRules.Count());
                Assert.AreEqual("Phone", validationEngine.BrokenRules[0].PropertyName);
            }

    If you are comfortable with the object.IsValid() format then take a look at the following article.

    Designing Application Using Test Driven Development

    In the post above I have used extension methods to add the IsValid() method to all the objects that inherit from the base class. This will give a more fluent interface when validating the objects but it will move away from Single Responsibility Principle. Creating the ValidationEngine as a separate class library will allow you to use it in different projects.

    In this post I explained the basics of creating a validation framework. If you have any other methods of techniques then please do share.