Recently, I had to implement validation on business objects in an already existing
project. The validation should ensure that the different classes in the business object
tier would validate them selves based on business rules. One of the rules on the Product
class was that the Price property never must be negative and the Name property must
be at least one character long.
For some reason I don’t know, none of these validation checks was made and I had to
find a simple way to implement the checks without changing the original code too much.
I’m a big fan of Rockford Lhotka’s CSLA.NET framework
which has a nice way of doing validation, so I used that as an inspiration.
In the spirit of CSLA.NET I wanted the boolean read-only property IsValid, that tells
whether or not the object is valid or not. I also wanted a read-only property called
ValidationMessage, which tells what rules are broke and how to correct them.
The business objects didn’t have a base class, so I decided to create one and add
as much of the validation code there. Here is that abstract class called ValidationBase:
using System;
using System.Text;
using System.Collections.Specialized;
public abstract class ValidationBase
{
private StringDictionary _BrokenRules
= new StringDictionary();
/// <summary>
/// Add
or remove a broken rule.
/// </summary>
/// <param
name="propertyName">The name of the property.</param>
/// <param
name="errorMessage">The description of the error</param>
/// <param
name="isBroken">True if the validation rule is
broken.</param>
protected void AddRule(string propertyName, string errorMessage, bool isBroken)
{
if (isBroken)
{
_BrokenRules[propertyName] = errorMessage;
}
else
{
if (_BrokenRules.ContainsKey(propertyName))
{
_BrokenRules.Remove(propertyName);
}
}
}
/// <summary>
/// Reinforces
the business rules by adding rules to the
/// broken
rules collection.
/// </summary>
protected abstract void Validate();
/// <summary>
/// Gets
whether the object is valid or not.
/// </summary>
public bool IsValid
{
get
{
Validate();
return this._BrokenRules.Count
== 0;
}
}
/// /// <summary>
/// If
the object has broken business rules, use this property to get access
/// to
the different validation messages.
/// </summary>
public string ValidationMessage
{
get
{
StringBuilder sb
= new StringBuilder();
foreach (string messages in this._BrokenRules.Values)
{
sb.AppendLine(messages);
}
return sb.ToString();
}
}
}
Then I hade to change all the business object so they derived from ValidationBase
and implement the Validate() method on each of them. That’s all the work needed in
order to start using the IsValid property. Here’s a dummy example of a derived class
that uses the validation feature in its Save() method:
using System;
public class Product : ValidationBase
{
#region Poperties
private int _Price;
public int Price
{
get { return _Price; }
set { _Price = value; }
}
private string _Name;
public string Name
{
get { return _Name; }
set { _Name = value; }
}
#endregion
#region Methods
public void Save()
{
// Only save if the object is valid,
// otherwise throw an exception.
if (IsValid)
{
DoSomething();
}
else
{
throw new Exception(ValidationMessage);
}
}
#endregion
#region Validation
/// <summary>
/// Reinforces
the business rules by adding rules to the
/// broken
rules collection.
/// </summary>
protected override void Validate()
{
AddRule("Price", "Price
must be greater than or equal to 0", this.Price
< 0);
AddRule("Name", "Name
must be set", string.IsNullOrEmpty(this.Name));
}
#endregion
}
It became a very simple implementation in the derived classes that didn’t demand
any big changes to the original code.
* Only $4.95/month ASP.NET & Windows 2008 + IIS 7 Hosting! FREE SQL Included