When using entity classes for your business layer; validation is always a concern. One of the techniques that I frequently use is based on the attribute based validation. The idea is to simply decorate the properties of the objects with custom attributes and let the validation framework handle the object validation.
Check out the Customer class below whose properties “FirstName” and “LastName” are decorated with the “NotNullOrEmpty” attribute.
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; }
}
The “NotNullOrEmpty” attribute is a simple custom attribute which derives from the abstract class ValidationAttribute.
public abstract class ValidationAttribute : System.Attribute
{
public string Message { get; set; }
public abstract bool IsValid(object item);
}
[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;
}
}
The validation is performed by the “ValidationEngine” class. There are several ways of providing the engine. In one of my articles I used extension method to provide the engine implementation within the BusinessBase class. You can view that article using the following link:
Designing Application Using Test Driven Development
In this post I have separated the engine into an isolated class called “ValidationEngine”.
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 client can now use the ValidationEngine using the following code:
class Program
{
static void Main(string[] args)
{
var customer = new Customer();
ValidationEngine.Validate(customer);
foreach(var brokenRule in customer.BrokenRules)
{
Console.WriteLine(brokenRule.Message);
}
}
}
The output is shown below:
