The IoC mind set: Validation

time to read 3 min | 406 words

I think that I mentioned that I believe that having a good IoC container at your disposable can make you really shift the way you are structuring your code and architects solutions.

Let us take for instance Validation as an example. The two examples that jump to mind are Castle.Components.Validation and the Validation Application Block. They both have the same general approach, you put an attribute on a property, and then you use another class to validate that the object meet its validation spec.

This approach work, and it is really nice approach, for very simple input validation. Required fields, length of a string, etc. Being able to declaratively specify that is so very nice. But it breaks down when you have more complex scenarios. What do I mean by that? After all, both libraries offers extensibility points to plug your own validators...

Well, as it turn out, when we go beyond the realm of simple input validation, we reach into the shark filled waters of business rules validation. Those rules are almost never applied across the board. Usually, they are very targeted.

Business rule: A customer may only open a service call for products that the customer has purchased

Expressing this rule in code is not very hard, but it doesn't benefit much from the above mentioned libraries.*

Nevertheless, you want to have some sort of a structure in your validation code. You want to be able to add new validation easily. Here is the back of the envelope solution for this. Hopefully it will make it clearer why I think that having IoC makes it so very easy to handle things.

public interface IValidatorOf<T>
{
   void Validate(T instance, ErrorSummary errorSummary);
}

public class Validator
{
	IKernel kernel;//ctor injection, not shown
	
	public ErrorSummary Validate<T>(T instance)
	{
		ErrorSummary es = new ErrorSummary();
		foreach(IHandler handler in kernel.GetHandlers(typeof(IValidatorOf<T>)))
		{
			((IValidatorOf<T>)handler.Resolve(CreationContext.Empty)).Validate(instance, es);
		}
		return es;
	}
}

And yes, that is the entire thing. Come to think about it, I think that we need to add GetAllComponentsFor<T>() to Windsor, but that is another matter. Now, if I want to add a new validation, I inherit IValidatorOf<T> with the right T, and that is it. It gets picked up by the container automatically, and the rest of your code just need to call Validator.Validate(myServiceCall); and handle the validation errors.

* Actually, a standard way to report validation errors is very nice.