Collecting Errors

Validation is a tough subject. One that I’m constantly trying to think of better ways of doing. Some suggest that all validation should occur in the domain, and some prefer to check if the object is valid before proceeding. I lean towards the idea of not allowing your objects to enter an invalid state. So far the easiest approach I have found to do this is to raise meaningful exceptions in the domain to ensure this.

However, when there are several reasons why an object can be considered "invalid" and, those reasons need to be reflected in the UI, I haven’t been able to figure out a clean way to do this in the domain. Suggestions are welcome.

Here’s an approach that we’ve taken to some of our validation, when user input needs to be checked so that we can provide meaningful error messages to the end user.

First we have 2 core validation interfaces:

public interface IValidationResult
{
    bool IsValid { get; }
    IEnumerable<string> BrokenRules { get; }
}

and

public interface IValidation<T>
{
    IValidationResult Validate(T item);
}

The IValidation<T> is in essence a form of a Specification. Now to collect the errors we use a visitor. The following are the core visitor interfaces.

public interface IVisitor<T>
{
    void Visit(T item_to_visit);
}

public interface IValueReturningVisitor<TypeToVisit, TypeToReturn> : IVisitor<TypeToVisit>
{
    void Reset();
    TypeToReturn Result { get; }
}

We have an implementation of a IValueReturningVisitor that collects errors from visiting IValidations, then returns a validation result.

public class ErrorCollectingVisitor<T> : IValueReturningVisitor<IValidation<T>, IValidationResult>
{
    private readonly T item_to_validate;
    private readonly List<string> results;

    public ErrorCollectingVisitor(T item_to_validate)
    {
        this.item_to_validate = item_to_validate;
        results = new List<string>();
    }

    public void Visit(IValidation<T> item_to_visit)
    {
        var validation_result = item_to_visit.Validate(item_to_validate);
        if (!validation_result.IsValid)
        {
            results.AddRange(validation_result.BrokenRules);
        }
    }

    public void Reset()
    {
        results.Clear();
    }

    public IValidationResult Result
    {
        get { return new ValidationResult(results.Count == 0, results); }
    }
}

And a handy extension method for returning the value from visiting a set of validations.

public static Result ReturnValueFromVisitingAllItemsWith<TypeToVisit, Result>(
    this IEnumerable<TypeToVisit> items_to_visit, IValueReturningVisitor<TypeToVisit, Result> visitor)
{
    visitor.Reset();
    items_to_visit.Each(x => visitor.Visit(x));
    return visitor.Result;
}

An example of the usage for the visit can be seen below:

public IValidationResult Validate(IUser user)
{
    return userValidations
        .Select(x => x as IValidation<IUser>)
        .ReturnValueFromVisitingAllItemsWith(new ErrorCollectingVisitor<IUser>(user));
}

Related Articles:

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

About Mo Khan

mO, is just a kid who's excited about writing software. He's a student of his profession, and just wants to share his thoughts on software development.
This entry was posted in Design Patterns. Bookmark the permalink. Follow any comments here with the RSS feed for this post.

7 Responses to Collecting Errors

  1. There are two more levels of validation:

    the one you’ve mentioned validates only objects, but sometimes you can’t create object because of incorrect user input and sometimes an error occur during saving object to the database for example. And all these issues should be reflected in UI in the same way.

  2. When I’m not using WebForms, I solve input validation by using Presentation Model, i.e. special crafted DTOs to collect&carry user input to validation service.

    To display notifications (validation/other errors) I use age old notification pattern, which simply is a collection of messages to display .

    I’ve also had my take on validation “framework” with empathis on fluent construction of validation rules which looked good enough for C# 2.0 Haven’t had a chance to come back to it with C# 3.0 yet :)

  3. @ Thomas:
    it’s one person having 2 blogs & crossposting.

  4. Mo says:

    Thanks Victor for clarifying that for me.

    I like what Michael posted in the comments at http://mokhan.ca/blog/CommentView,guid,36584ca0-a20f-4df4-acdc-c844d15c0b2f.aspx#commentstart

    He suggested a fluent interface for validation…

    CreateRule.For()
    .Property(u => u.FirstName)
    .WithRule((u, value) => !value.IsNullOrEmpty())
    .WithError(“First name is required”);

    This would allow me to validate a DTO instead of a domain object, for messages to return to the UI, and that would allow me to ensure the domain does not enter an invalid state. So user.change_first_name_to(first_name); would throw if it was invalid. However, this might violate DRY.

    @Maxim
    As far the database validation goes, I suppose if we were to ensure that our domain object do not enter an invalid state that would reduce our chances for allowing bad data into the db. Our layers of protection, would be js validation in the ui, plus dto validation in service, and throw exception from the domain if it gets that far.

    I think I’m ranting… but perhaps this suggests that I could use some more guidance in “validation”, or at least a working example!

  5. jcteague says:

    @Maxim, I disagree. If you have a lot of logic surounding your domain classes, that logic should be contained withing a factory class. You can still use the same message collection pattern for those scenarios.

    As far as database errors goes, the user does not care about those. There is nothing user can do. In that case a system error should be displayed, through UI general error handling system.

    We were talking at Kaizenconf about advanced uses of IOC containers and vailidation came up. Ayende has an old blog entry about it, sorry I don’t have the link handy, but you might want to search for it.

  6. Probably you mean this one:

    http://ayende.com/Blog/archive/2007/10/21/The-IoC-mind-set-Validation.aspx

    But there are situations when it is better to show a field-level error when a database error occurs