sobota, 15 sierpnia 2015

Validation night - FluentValidation vs DataAnnotations

Time to do some model validation on my entities. There are many ways to do that, but most common is using DataAnnotations. I really don't like that solution, because it makes my models so ugly that I have to edit them with eyes closed.

I was wondering about reasonable alternatives and by reasonable I mean 'not writing entire framework from scratch' or even 'do it as small and clean as possible'. First guess was to look for entity mapping based validation, but that lead me into darkness, but searching for fluentapi validation returned library with really promising name FluentValidation. Saving you the trouble, here's the link.
I really liked it thanks to extreme simplicity both in implementation and testing.

Lets start with clean model to see what do we have.
Simple class to describe some person. What do I expect from each of my employees?

  • Name has to be between 2-20 chars
  • FamilyName can be little longer, lets say 2-30 chars
  • must have both of them plus ContactInformation 
I went for multiple assertions in one case to reduce length of code...
...[time passing]...
I have started with DataAnnotations tests and it took me a while to discover some nice way to do that.

Here's my Employee decorated with validation attributes. I don't really care yet about messages that will be displayed on the view, but here's how you can define them (it probably would be good idea to place them in concrete language file).
In the begining I've just wanted to be sure that created instance of Employee is valid so I can proceed with the properties. It would be pain in the ass to write methods for all the scenarios and this is just simple validation of three properties. To make my life easier I have created usefull method IsPropertyValid that takes property name as first parameter and all the following are just generic params so I can pass all the possibilities to check at once. For testing different models that method could be moved to abstract class, but lets stick to that one.
That was quite an excercise, but nice test doesn't mean I'm going to forgive all the attributes in my model (or it's ViewModel, yes you can create different view models for your entities to use different validation for specific scenarios, but nope).
Now the way I liked more. After acquiring FluentValidation I've had to attach it to my application. This is simply done by adding FluentValidationModelValidatorProvider.Configure(); in MvcApplication constructor. (it's hiding under Global.asax)
Next step is to create custom validator inheriting from AbstractValidator
After that I'm ready to test (and happy too, because my model is cleaner than the perfect housewife herself). Now FluentValidation provides with its own assertion methods that verify if validation error will occur if we pass specified value to property defined by Expression. There's just one attribute to add so the model will be validated later on by the controller. So the same Employee but with less garbage inside and its tests. There's one more assertion method, ShouldHaveChildValidator but I didn't see the point using it in this case as ContactInformation is being validated separately by it's own controller. For dessert tests outcome, differences may be interesting if you take performance as priority.

Brak komentarzy:

Prześlij komentarz