ASP.NET MVC
ASP.NET MVC

Complex validation in MVC and web apps, using FluentValidation


Most projects require some sort of form input. And additionally, those form inputs need to be validated. For the validation, ASP.NET developers have a lot of options, but the default one is pretty good. That is the DataAnnotations. Those give you the option of specifying a lot of the validation requirements declaratively:

The upside of this is that you get out of the box support for a lot of common checks, but also stuff like client-side validation. But sometimes you need a bit more. Specifically, you validation logic might need to go into the database (through your service layer, of course), and make sure that no user has already registered with that exact email address. That type of validation was a requirement in most all of the (serious) projects I did in the last couple of years. And when that is the case, I turn to FluentValidation.

Quick Introduction to FluentValidation

What FluentValidation does is it allows you to use a fluent interface and lambda expressions for building validation rules. That means that you can now express your validation rules like this:

What the above code does, is attach rules to the CashierViewModel (this tells it so: AbstractValidator<CashierViewModel> ) and it defines one specific rule, that the PIN code must be unique across the tenant – so, no two cashiers within a single tenant can have the same PIN code. It’s a business requirement. But our validator is in the presentation layer, and to make sure this rule is obeyed, we need to go down to the database layer across the service layer. Because of Dependency Injection (more on that soon) our validators are instantiated with all the dependencies injected into them ( CashierValidator(IPrincipalService principalService) ).

How does that work with the Data Annotations attributes?

It doesn’t. For one, using both causes problems. Specifically, if you submit a form with both validations, one of those sets of rules will get evaluated first, and if there is an error, the other set won’t even be checked. That means the user will be presented with an incomplete list of validation errors.

Another great point is that I want my code & architecture to be consistent. That means that I don’t really want some part of my validation logic to be written in the Validator classes, and another one on the models.

Hammering the point home is that sometimes, I don’t use ViewModels (I have a fairly pragmatic approach there, if I don’t need it, I don’t add it) – which means that I would have to decorate my “domain models” or worse, my database objects with some validation logic that will be used on the UI, or implement validation using these annotations on the bottom layers. It makes much more sense to reuse the validation logic across the layers. FluentValidation allows you to do that as well and the code actually makes sense.

Integrating FluentValidation into the UI…

If you’re anything like me, you want as much as possible done behind the scenes, automagically. One such thing for me, is drawing the required asterisk next to required fields. Like this:

Screen Shot 2015-09-08 at 21.28.44

 

So, to do this, you can basically put something like this in your Editor Templates:

So now, every time you render an editor for a model property ( @Html.EditorFor(x => x.Name)) you get a nice input box with all the proper attached styles. The required class in our case renders the asterisk:

The above code is LESS. If you’re not familiar with it and you’re doing any front-end, go look at it, now!

However, if you don’t have a [Required]  attribute on your model property, the ModelMetadata.IsRequred  won’t get set by default. Unless, you trick it and write your own ModelMetadataProvider. In that, you can actually look inside the rule for that particular model and force it to set that. Here’s my code for it:

The above code is not perfect, far from it. For example it has a double iteration over the validators, etc., it also only supports the IsRequired  part, but you can get the general idea from it.

So there you go, that’s how I use FluentValidation to replace DataAnnotations on my ViewModels and still manage to use the underlying functionality (ModelMetadata) to get as much of the awesome done automagically.


Anže Vodovnik is a proud father, enthusiastic guitarist and passionate software developer. He enjoys presenting at conferences sharing his experience of over 15 years of creating software. He was briefly a Microsoft MVP for Azure before forfeiting the title when he joined Microsoft UK, where he’s now working hand-in-hand with customers to help them develop and use solutions based on the Microsoft Azure platform.

View Comments