Monthly Archives: May 2009
Fluent Validation Model Binder – Asp.net MVC
A few weeks ago I found the Fluent Validation framework by Jeremy Skinner. I needed to conditionally validate a model depending on an application setting. eg. Description field mandatory / not mandatory depending on the clients business requirements. I loved the simplicity of the framework and the separation from the model it provided.
Since then I have submitted a few patches for the framework, one of which is the Fluent Validation Model binder. Inspired by the Data Annotations Model binder, it works in much the same way. Once you have it set to your default model binder, it will validate any model which contains the specific attribute. This will become clear in the examples below.
Firstly lets take our model.
[Validator(typeof(LineItemValidator))] public class LineItem { public int LineNumber { get; set; } public DateTime Date { get; set; } public string Description { get; set; } public decimal Net { get; set; } public decimal Tax { get; set; } public decimal Gross { get; set; } } |
Attached to this simple LineItem class is a Validator attribute. This attribute is used by the Model Binder to locate the Class used for validation. Below I will define my LineItemValidator class which will hold the rules for the validation.
|
As you can see the class must inherit from AbstractValidator<T> where T is the model you want to define the rules for. The first rule uses the conditional When clause where it will only validate that the field is NotEmpty when the Settings.DescriptionRequired boolean is true. Also, another thing is the complex validation taking place on the Gross field. Not only does it validate that it is greater than 0, but that the value is equal to the net + tax amount. This is very elegant indeed. I have also specified the ‘WithName’ clause which has also been integrated into the model binder so that if an error occurs with the gross field, the WithName value will be displayed when an error happens. This is extremely handy for language localization or when the name of the field on the Model is insufficient.
Wiring this Model binder up in the Application_start event in the global.asax.cs is as easy as this.
|
Note that we have to pass an instance of the AttributedValidatoryFactory into the Model Binder. This means if you have an alternate way of locating the Validator class other than via the attribute you can inherit from IValidatorFactory and create your own.
Now when a parameter of LineItem gets passed into a controller it will be validated against the model and all errors placed into the ModelState. This can then check the isValid property to determine if there are any errors and proceed accordingly.
[AcceptVerbs(HttpVerbs.Post)] public ActionResult Edit(List<LineItem> lineItems) { if (ModelState.IsValid) return RedirectToAction("Edit"); return View(); }
|
And that’s it. I hope you enjoy using the Fluent Validation framework as much as I have and happy coding. For all you guys waiting for xVal integration, I will try and post a solution in the coming week.
Adam