Entity validation with visitors and extension methods

On the Yahoo ALT.NET group, an interesting conversation sprung up around the topic of validation.  Entity validation can be a tricky beast, as validation rules typically depend on the context of the operation (persistence, business rules, etc.).

In complex scenarios, validation usually winds up using the Visitor pattern, but that pattern can be slightly convoluted to use from client code.  With extension methods in C# 3.0, the Visitor pattern can be made a little easier.

Some simple validation

In our fictional e-commerce application, we have a simple Order object.  Right now, all it contains are an identifier and the customer’s name that placed the order:

public class Order
{
    public int Id { get; set; }
    public string Customer { get; set; }
}

Nothing too fancy, but now the business owner comes along and requests some validation rules.  Orders need to have an ID and a customer to be valid for persistence.  That’s not too hard, I can just add a couple of methods to the Order class to accomplish this.

The other requirement is to have a list of broken rules in case the object isn’t valid, so the end user can fix any issues.  Here’s what we came up with:

public class Order
{
    public int Id { get; set; }
    public string Customer { get; set; }

    public bool IsValid()
    {
        return BrokenRules().Count() > 0;
    }

    public IEnumerable<string> BrokenRules()
    {
        if (Id < 0)
            yield return "Id cannot be less than 0.";

        if (string.IsNullOrEmpty(Customer))
            yield return "Must include a customer.";

        yield break;
    }
}

Still fairly simple, though I’m starting to bleed other concerns into my entity class, such as persistence validation.  I’d rather not have persistence concerns mixed in with my domain model, it should be another concern altogether.

Using validators

Right now I have one context for validation, but what happens when the business owner requests display validation?  In addition to that, my business owner now has a black list of customers she won’t sell to, so now I need to have a black list validation, but that’s really separate from display or persistence validation.  I don’t want to keep adding these different validation rules to Order, as some rules are only valid in certain contexts.

One common solution is to use a validation class together with the Visitor pattern to validate arbitrary business/infrastructure rules.  First, I’ll need to define a generic validation interface, as I have lots of entity classes that need validation (Order, Quote, Cart, etc.):

public interface IValidator<T>
{
    bool IsValid(T entity);
    IEnumerable<string> BrokenRules(T entity);
}

Some example validators might be “OrderPersistenceValidator : IValidator<Order>”, or “CustomerBlacklistValidator : IValidator<Customer>”, etc.  With this interface in place, I modify the Order class to use the Visitor pattern.  The Visitor will be the Validator, and the Visitee will be the entity class:

public interface IValidatable<T>
{
    bool Validate(IValidator<T> validator, out IEnumerable<string> brokenRules);
}

public class Order : IValidatable<Order>
{
    public int Id { get; set; }
    public string Customer { get; set; }

    public bool Validate(IValidator<Order> validator, out IEnumerable<string> brokenRules)
    {
        brokenRules = validator.BrokenRules(this);
        return validator.IsValid(this);
    }
}

I also created the “IValidatable” interface so I can keep track of what can be validated and what can’t.  The original validation logic that was in Order is now pulled out to a separate class:

public class OrderPersistenceValidator : IValidator<Order>
{
    public bool IsValid(Order entity)
    {
        return BrokenRules(entity).Count() > 0;
    }

    public IEnumerable<string> BrokenRules(Order entity)
    {
        if (entity.Id < 0)
            yield return "Id cannot be less than 0.";

        if (string.IsNullOrEmpty(entity.Customer))
            yield return "Must include a customer.";

        yield break;
    }
}

This class can now be in a completely different namespace or assembly, and now my validation logic is completely separate from my entities.

Extension method mixins

Client code is a little ugly with the Visitor pattern:

Order order = new Order();
OrderPersistenceValidator validator = new OrderPersistenceValidator();

IEnumerable<string> brokenRules;
bool isValid = order.Validate(validator, out brokenRules);

It still seems a little strange to have to know about the correct validator to use.  Elton wrote about a nice trick with Visitor and extension methods that I could use here.  I can use an extension method for the Order type to wrap the creation of the validator class:

public static bool ValidatePersistence(this Order entity, out IEnumerable<string> brokenRules)
{
    IValidator<Order> validator = new OrderPersistenceValidator();

    return entity.Validate(validator, brokenRules);
}

Now my client code is a little more bearable:

Order order = new Order();

IEnumerable<string> brokenRules;
bool isValid = order.ValidatePersistence(out brokenRules);

My Order class doesn’t have any persistence validation logic, but with extension methods, I can make the client code unaware of which specific Validation class it needs.

A generic solution

Taking this one step further, I can use a Registry to register validators based on types, and create a more generic extension method that relies on constraints:

public class Validator
{
    private static Dictionary<Type, object> _validators = new Dictionary<Type, object>();

    public static void RegisterValidatorFor<T>(T entity, IValidator<T> validator)
        where T : IValidatable<T>
    {
        _validators.Add(entity.GetType(), validator);
    }

    public static IValidator<T> GetValidatorFor<T>(T entity)
        where T : IValidatable<T>
    {
        return _validators[entity.GetType()] as IValidator<T>;
    }

    public static bool Validate<T>(this T entity, out IEnumerable<string> brokenRules)
        where T : IValidatable<T>
    {
        IValidator<T> validator = Validator.GetValidatorFor(entity);

        return entity.Validate(validator, out brokenRules);
    }
}

Now I can use the extension method on any type that implements IValidatable<T>, including my Order, Customer, and Quote classes.  In my app startup code, I’ll register all the appropriate validators needed.  If types use more than one validator, I can modify my registry to include some extra location information.  Typically, I’ll keep all of this information in my IoC container so it can all get wired up automatically.

Visitor patterns are useful when they’re really needed, as in the case of entity validation, but can be overkill sometimes.  With extension methods in C# 3.0, I can remove some of the difficulties that Visitor pattern introduces.

Related Articles:

Post Footer automatically generated by Add Post Footer Plugin for wordpress.

About Jimmy Bogard

I'm a technical architect with Headspring in Austin, TX. I focus on DDD, distributed systems, and any other acronym-centric design/architecture/methodology. I created AutoMapper and am a co-author of the ASP.NET MVC in Action books.
This entry was posted in C#, Patterns. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • http://www.lostechies.com/blogs/sean_chambers Sean Chambers

    Wow! what an excellent post.

    I was following the discussion on the ALT.net group and this is a great compilation of the knowledge from that thread.

    I was starting to employ this in my next project but didn’t get to refactor to visitors yet so I havent used it.

    You did a great job compiling all the information into one blog post. keep it up!!

  • http://www.lostechies.com/blogs/joe_ocampo/ Joe Ocampo

    I am getting flashbacks of the CSLA!!!

  • http://www.lostechies.com/blogs/joe_ocampo/ Joe Ocampo

    I question the term Validator in relation to DDD. Since the operation of the Validator seems to be a simple predicate based on business rule shouldn’t the term Specification [Evans Pg227] be used instead?

  • http://grabbagoft.blogspot.com/ Jimmy Bogard

    @Joe

    It looks like validators and specs are doing the same thing: look at an object, and return true or false if it matches some specification.

    The difference is specs are usually done for positive matching of individual customer-related specs, like “ColorSpec” or “GrossWeightSpec”. These specs can be collected through a composite spec to perform a search on the repository.

    Validators however are used to perform negative matching of a collection of concerns in one single context. For example, a single persistence validator performs all matching logic on every pertinent aspect of a single entity, not a collection of entities in a repository.

    You know, great questions like these just deserve a post…

  • Tapio Kulmala

    You have an error in your examples :

    public bool IsValid(Order entity)
    {
    return BrokenRules(entity).Count() > 0;
    }

    It very likely should be :

    public bool IsValid(Order entity)
    {
    return BrokenRules(entity).Count() == 0;
    }

  • http://grabbagoft.blogspot.com/ Jimmy Bogard

    @Tapio

    Thanks for the find! Looks like my logic was backwards there…serves me right for not having tests

  • http://www.tobinharris.com Tobin Harris

    Nice idea. Where do you put validation checks for something that involves an entire set . For example, when validating a user, I want to make sure they have a unique email address. Do you pass a repository in to the newUser.Validate(…) (I feel this is bad)

  • http://www.lostechies.com/members/bogardj/default.aspx bogardj

    @Tobin

    For things like that, I’ll put the validation on whatever handles the command/operation. Things like unique email address aren’t necessarily validation for a single entity, but rather a set of entities, so I’ll put that validation in an operation that does UpdateUser or something similar.

    Right now, we have 3 levels of validation: user input validation, operational consistency validation (business logic), and entity self-consistency validation.

  • Dmitriy Shvadskiy

    How do you reuse rules across validators? Say OrderPersistanceValidator and OrderReadyToShipValidator have common rule:
    OrderShipDate >= Today

  • http://www.lostechies.com/members/bogardj/default.aspx bogardj

    @Dmitriy

    To be honest, that’s not come up for me yet. I can imagine some ways of doing it, maybe by breaking specific rules out into individual rules classes etc.

  • Chev

    really enjoyed the article.

    Would it be possible to get a sample app?

  • http://www.lostechies.com/members/bogardj/default.aspx bogardj

    @Chev

    Well, unfortunately the _real_ code is in a proprietary NDA app, and the sample code from above I lost about a year ago. Sorry…

  • Eugene

    Validator class should be static if you want to use extension method

  • Adam

    To avoid iterating the entire set of broken rules when you don’t need to you could shortcut IsValid to return false as soon as BrokenRules yields anything:

    return BrokenRules(entity).Any();

    On a side note, it seems harsh that you have to run the rules twice (less so with the shortcut above) in the implementing code in order to get both the rules collection and the IsValid status, which gets another rules collection.

  • Adam

    err…I guess that would need a negation for the name “IsValid”:

    return !BrokenRules(entity).Any();

  • http://www.cuttingedge.it/blogs/steven/ Steven

    Very nice. I wrote a blog post over a year back that describes such a mechanism in the ‘context’ of the validation application block. The trick I used was to use a [ThreadStatic] variable to sending a unit of work (such as LINQ to SQL’s DataContext and Entity Framework’s ObjectContext) to validators lower on the call stack. You can read more about it here: http://www.cuttingedge.it/blogs/steven/pivot/entry.php?id=47.

    Cheers

  • indiecodemonkey

    okay, what if I needed a database look-up before persisting the Order? In this case, neither of the two properties would really need it, but in some cases, Entities that requires a unique name (or something along those lines) would need check all existing names first, then persist. Would it be possible to inject Repositories or Services into the OrderPersistenceValidator?

  • Pingback: Validating domain model using extension methods | PHP Developer Resource

  • Nimam51

    that was great and i used it in my apps. but what about duplication validation logic in my inheritance tree? Person <—–Employee  which Employee has common properties in reside in Person so some Resistancy validation already defined in Persone validator.
    my workaround is to use aggregation in validators (use persone validator in employee validator). any better idea?

  • Pingback: DDD Validation | C#Net

  • Pingback: On Validation | eric.polerecky

  • Masoud Sanaei

    Great idea, could you please show the startup code for registering the validators, also?

  • Parth

    First of all, I must say this is a great article. However, I am bit confused about how to associate multiple validator to a single entity. Let’s say I need different rules to validate customer on the basis of the create date and other field values. How could I do that by injecting 2 different Validator? Should I use constructor to pass IEnumerable<IValidator>? Any suggestion?

    • jbogard

      Wow, this is an old post. I use Fluent Validation these days, which supports multiple validators.

      • Parth

        Personally, I’m not a big fan of unnecessary use of reflection. But in case of Fluent API, I always loved it!!! However, I figured there is one another way. Yesterday I have quickly created ValidatorFactory that picks up multiple validators automatically and validate entity in service layer. Btw, I pass the validationFactory object in the constructor of service. As per the initial testing it’s works like a charm, even with the composite validation logic depends on multiple entities. :-) Thanks for putting the validator idea in my head.

      • Masoud Sanaei

        Do yo means http://fluentvalidation.codeplex.com/ or another thing?

        • jbogard

          There’s nothing really to update – the fluent validation docs pretty much cover it.