Self-Configuring Enterprise Library Validation

A recent project used Enterprise Library Validation to validate domain objects, and needed it configured for a web front end, a WCF front end, and (of course) unit tests. The same configuration in 3 different places didn't strike me as very DRY, so I figured hey - why not have it configure itself? Here's a quick paraphrase of how I did it.

I started with an abstraction of the validation service:

public interface IValidationService
{
    bool IsValid<T>(T objectToValidate) where T : class;
}

...which I implemented like so:

using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Reflection;
using Microsoft.Practices.EnterpriseLibrary.Validation;
 
public class SelfConfiguringEnterpriseLibraryValidationService : IValidationService
{
    private static readonly Dictionary<Type, Validator> _validators = GetConfiguredValidators();
 
    public bool IsValid<T>(T objectToValidate) where T : class
    {
        if (!_validators.ContainsKey(typeof(T)))
        {
            return true;
        }
 
        ValidationResults results = _validators[typeof(T)].Validate(objectToValidate);
 
        return results.IsValid;
    }
 
    private static Dictionary<Type, Validator> GetConfiguredValidators()
    {
        /* Further down the page :) */
    }
}

...fairly straightforward: a static-scoped _validators Dictionary of Validator objects keyed by the Type of object they validate, and an implementation of IsValid() which looks up the appropriate Validator, and uses it to validate the object if it exists.

The nitty gritty of this class is the GetConfiguredValidators() method, which puts together the Dictionary of Validators. It uses an extension method I've mentioned before which gets all the available deployed Types, and goes a bit like this:

private static Dictionary<TypeValidator> GetConfiguredValidators()
{
    Dictionary<TypeValidator> validators = new Dictionary<TypeValidator>();
 
    // Get all the available deployed Types;
    IEnumerable<Type> availableTypes = Assembly.GetExecutingAssembly().GetAvailableTypes(
        a => a.FullName.StartsWith("MyNamespace."), // <- only Assemblies we've written
        t => !(t.IsAbstract || t.IsInterface));     // <- only concrete Types
 
    IEnumerable<Type> validatorTypes = availableTypes
        .Where(t => typeof(Validator).IsAssignableFrom(t))
        .ToArray()
 
    validatorTypes.ForEach(vt =>
    {
        Type validatedType = null;
 
        if (vt.IsGenericType)
        {
            // This Validator inherits from Validator<T>, so register it against T:
            validatedType = vt.GetGenericArguments().First();
        }
        else
        {
            // This is a non-generic Validator, so I'm going to rely on a convention;
            // it should be named [ValidatedType]Validator, so I can get the validated
            // Type from the name:
            string validatedTypeName = vt.Name.Replace("Validator"null);
            validatedType = availableTypes.First(t => t.Name == validatedTypeName);
        }
 
        // Create an instance of the Validator; Validators have a constructor which
        // takes a NameValueCollection, so supply one of those:
        // Instead of Activator.CreateInstance(), you can use this:         // Validator validator = (Validator)vt.GetInstance(new NameValueCollection());         Validator validator = (Validator)Activator.CreateInstance(vt, new NameValueCollection());         validators.Add(validatedType, validator);     });     return validators; }

I then used Unity to plug the implementation in behind the interface, and that's it.

There's a few things to note about this implementation:

  1. As per the notes, it relies on non-generic Validators following a particular naming convention
  2. It assumes each domain object Type should always be subject to the same validation; it makes no provision for Validation RuleSets
  3. It assumes there's only a single Validator Type for each validated Type

These issues could all be dealt with fairly easily using:

  1. Attributes for non-generic Validators to declare what Type they validate
  2. Attributes for Validators to label themselves as belonging to a particular Validation RuleSet
  3. A List<Validator> being used as the _validators Dictionary value

It works nicely, and I was quite pleased to delete my validation config :)

Print | posted @ Friday, March 25, 2011 9:41 PM

Comments on this entry:

No comments posted yet.

Post A Comment
Title:
Name:
Email:
Comment:
Verification: