Click here to Skip to main content
Click here to Skip to main content

FluentValidation and Unity

By , 13 Feb 2012
Rate this:
Please Sign up or sign in to vote.

Introduction

Validation is often the bane of a development project. It's critical to usability and data integrity (and often security, when ensuring data is not an attempt to attack the application), but it can be very time consuming to write the validation code and handle all of the permutations. Luckily Jeremy Skinner has created an excellent open source validation framework called Fluent Validation for .NET. Jeremy has created a lot of documentation, so this article will not cover the features and usage of Fluent Validation for .NET. One feature the documentation does not cover is how to pass the validation object via dependency injection when using Unity, which is an Inversion of Control (IoC) container. This article addresses how to do this. For the attached example I've used Silverlight, but the same techniques can be used with WPF.

Background

Dependency injection is a useful pattern to acheive loose coupling and also simplify testing by allowing dependencies to be stubbed or mocked. By being able to pass a validation object into a business object or view model (in the case of MVVM), tests can be written for the business object or view model without requiring the business object or view model to be valid. The validation object can be stubbed to always pass or fail as required.

This article does not cover unit tests, mocking, and dependency injection. It is assumed that the reader is already conversant with these techniques.

Using the code

The first step is to create a Unity validator factory from the ValidatorFactoryBase provided by Fluent Validation for .NET. The important code is the override for CreateInstance, which allows the factory to return the correct validation object from the Unity container.

public class UnityValidatorFactory : ValidatorFactoryBase
{
    private readonly IUnityContainer _container;

    public UnityValidatorFactory(IUnityContainer container)
    {
        _container = container;
    }

    public override IValidator CreateInstance(Type validatorType)
    {
        return _container.Resolve(validatorType) as IValidator;
    }
}

The next step is to register the factory with the Unity container. In the attached example, this is done in the Bootstrapper.cs class.

Container.RegisterType<IValidatorFactory, UnityValidatorFactory>(new ContainerControlledLifetimeManager());

Now the validation class can be created by inheriting from the AbstractValidator base class. See Fluent Validation for .NET documentation for more information about how to build validation rules from this base class.

public class MainPageViewModelValidator : AbstractValidator<IMainPageViewModel>
{
    public MainPageViewModelValidator()
    {
        RuleFor(x => x.FirstName)
            .NotEmpty()
            .WithMessage("First name cannot be blank.");

        RuleFor(x => x.LastName)
            .NotEmpty()
            .WithMessage("Last name cannot be blank.");

        RuleFor(x => x.Age)
            .NotEmpty()
            .WithMessage("Age is required.");

        RuleFor(x => x.Age)
            .Must(a => a.IsInt32())
            .When(x => !x.Age.IsNullOrEmpty())
            .WithMessage("Age must be an integer.");
    }
}

The validation class must also be registered with Unity. In the attached example, this is also registered in Bootstrapper.cs. The IValidator generic interface is assigned the interface for the view model and the registered implementation is the view model validator.

Container.RegisterType<IValidator<IMainPageViewModel>, MainPageViewModelValidator>(new ContainerControlledLifetimeManager());

Now a ViewModel can access the validation object by passing the validation factory in as a dependency and requesting the required validation object.

using FluentValidation;

private readonly IValidator<IMainPageViewModel> _validator;

public MainPageViewModel(IValidatorFactory validatorFactory)
{
    _validator = validatorFactory.GetValidator<IMainPageViewModel>();
}

The validation object can then be used as required, either validating the whole view model, or just a property (which can be useful when implementing IDataErrorInfo, as shown in the attached example). An example of validating a property is shown below. Note that a validation object can return more than one error, so the ValidationResult contains an Errors collection.

public string FirstName
{
    get { return _firstName; }
    set
    {
        if (_firstName != value)
        {
            _firstName = value;
            RaisePropertyChanged("FirstName");
        }

        // validate - even if no change
        ClearError("FirstName");
        var validationResult = _validator.Validate(this, "FirstName");
        if (!validationResult.IsValid)
        {
            validationResult.Errors.ToList().ForEach(x => SetError("FirstName", x.ErrorMessage));
        }
    }
}

History

  • July 2011 - initial release.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Craig Jewiss
Software Developer (Senior)
Australia Australia
I've been building line of business applications since 2002, mainly for finance and insurance companies in Australia.
Follow on   Twitter

Comments and Discussions

 
QuestionBinding Pinmemberdienecode10-Aug-12 15:36 
QuestionBinding Exceptions PinmemberNatural Born Koda4-Jul-12 4:23 
AnswerRe: Binding Exceptions PinmemberCraig Jewiss5-Jul-12 19:06 
Questionhave you consider EntLib Validation Application Block? PinmemberMichael Freidgeim29-Jun-12 15:02 
AnswerRe: have you consider EntLib Validation Application Block? PinmemberCraig Jewiss5-Jul-12 19:08 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web03 | 2.8.140415.2 | Last Updated 13 Feb 2012
Article Copyright 2012 by Craig Jewiss
Everything else Copyright © CodeProject, 1999-2014
Terms of Use
Layout: fixed | fluid