World’s simplest validation “framework” in .NET 3.5

Recently I’ve faced an interesting problem. The task engine for the xLim 2 type of architecture had to package some internal data and send it to the 3rd party business server. That remote server performed simple validation and then checked every submitted entity against internal business rules (it has a lot of these). The rules are checked one by one, and as soon as any rule fails, the failure result is returned along with the error description.

For some strange reason the validation takes a huge amount of time, and only the first failure is returned.

Obviously that’s not the friendliest integration situation. To prevent delays in the xLim 2 workflows I had to get some rules out of the server’s documentation and implement them in a scoped manner (you check all the rules that you can and then move to the next scope if there are no blocker errors).

The interesting part here is that only two small classes were needed to implement all the required validation rules without any reflection.

Simple generic rule class:

public sealed class Rule<T>
{
  private readonly Func<T, bool> _body;
  private readonly Func<T, string> _error;

  public Rule(Func<T, bool> body, Func<T, string> error)
  {
    _body = body;
    _error = error;
  }

  public bool IsValid(T item)
  {
    return _body(item);
  }

  public string GetError(T item)
  {
    return _error(item);
  }
}

Extension class from the same namespace:

public static class RuleExtension
{
  public static void Add<T>(this ICollection<Rule<T>> rules,
    Func<T, bool> assert, string error)
  {
    rules.Add(new Rule<T>(assert, c => error));
  }
  public static void Add<T>(this ICollection<Rule<T>> rules,
    Func<T, bool> assert, Func<T, string> error)
  {
    rules.Add(new Rule<T>(assert, error));
  }

  public static void Validate<T>(this ICollection<Rule<T>> rules,
    T item, IScope scope)
  {
    foreach (Rule<T> rule in rules)
    {
      if (!rule.IsValid(item))
      {
        scope.Write(rule.GetError(item));
      }
    }
  }
}

With that simple code I was able to declare different rules in quite compact manner.

Rule declaration:

var rules = new List<Rule<Project>>();
rules.Add(p => p.Starts < p.Ends, Resources.ProjectEndShouldBeAfterStart);
rules.Add(p => p.Budget >= 0, Resources.BudgetMustBePositive);
rules.Add(p => p.Ends > DateTime.Now,
  p => string.Format(Resources.Date0CantBeInPast, p.Ends));

And in order to validate some project instance against this rule-set, you just need to call Validate method (you can use simple ILog implementation instead of the IScope for this reference).

Validation:

rules.Validate(project, projectScope);

The rule-sets could be organized in extension modules and registered into the IoC system by name. Then you’d just load the proper set for the proper validation scope and run it.

This simple “framework” could be easily extended (yes, that just requires more of these small extension methods) to support more complex patterns like:

rules.IsNotNullOrEmpty(p => p.Name, "Name");
rules.CheckRegex(p => p.Code, new Regex("[A-Z]{4,6}"), "Code");
rules.ValidateStringLength(p => p.Name, 5, 10, "Name");

This approach is faster than the attribute based validation (check out the Validation Application Block for the example of that), simpler (just count the classes in VAP), and it separates validation logic from the actual business objects (you do not need to recompile your business objects if the validation logic has been changed.

This code feels to be quite efficient for the 30 minutes it took to write and cleanup it. And it has some decent chances of making it into the core shared libraries of the current xLim 2 implementation.

I wonder, if VAB can do something that’s not possible here…

0 Responses to “World’s simplest validation “framework” in .NET 3.5”


  1. No Comments

Leave a Reply