Search This Blog

Thursday, August 19, 2010

Add validation to business objects(using abstract)

Add validation to business objects
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();

///
/// Add or remove a broken rule.
///

/// The name of the property.
/// The description of the error
/// True if the validation rule is broken.
protected void AddRule(string propertyName, string errorMessage, bool isBroken)
{
if (isBroken)
{
_BrokenRules[propertyName] = errorMessage;
}
else
{
if (_BrokenRules.ContainsKey(propertyName))
{
_BrokenRules.Remove(propertyName);
}
}
}

///
/// Reinforces the business rules by adding rules to the
/// broken rules collection.
///

protected abstract void Validate();

///
/// Gets whether the object is valid or not.
///

public bool IsValid
{
get
{
Validate();
return this._BrokenRules.Count == 0;
}
}

/// ///
/// If the object has broken business rules, use this property to get access
/// to the different validation messages.
///

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

///
/// Reinforces the business rules by adding rules to the
/// broken rules collection.
///

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.

No comments:

Post a Comment