Validating multiple properties with FluentValidation

I really like Jeremy Skinner’s FluentValidation library and have used it on a couple of projects. Up until now though, I’ve only be using it to validate single properties in isolation.

The other day a colleague and I were trying to create a rule that validated two properties by querying the database and checking that the combination didn’t already exist. But we couldn’t seem to work it out.

I cheekily pinged @JeremySkinner and he helpfully pointed out that there are several ways of validating multiple properties:

  • if you want to do cross property comparison then RuleFor(x => x.Foo).GreaterThan(x => x.Bar) etc
  • you can also use Must: RuleFor(x => x.Foo).Must((instance, foo) => …)
  • usually those cover most scenarios. If not, then there’s also Custom, but that’s usually a last resort

The second option was what worked for us, and here is an example.

public class FooBarRequestValidator : AbstractValidator<FooBarRequest>
{
    private readonly IRepository repository;

    public FooBarRequestValidator(IRepository repository)
    {
        this.repository = repository;

        RuleFor(x => x.Foo)
		.Must(NotAlreadyHaveABar)
		.WithMessage("You already have a bar for this foo.");
    }

    private bool NotAlreadyHaveABar(FooBarRequest instance, string foo)
    {
        return !repository.GetAll<FooBar>()
		.Any(x => x.Foo == foo && x.Bar == instance.Bar);
    }
}

The trick is using the overload of Must() that takes a Func<T, TProperty, bool> predicate: that gives you access to the whole instance for your validating pleasure. Here, in NotAlreadyHaveABar() I can access Bar even though the rule is for the Foo property.

This works with FluentValidation v1.1 up to v2.0 Beta 1.

Advertisement

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s