Julian Jelfs’ Blog

Dynamic validation with FluentValidation and MVC 4

Posted in MVC, Uncategorized by julianjelfs on March 7, 2013

FluentValidation is a very nice way to perform custom validations in .Net and integrating it into the built in validation system used in MVC 4 is relatively straightforward. But it is not immediately clear how you go about performing dynamic validation on a MVC model based on the state of that model. If you are implementing a workflow, for example, this is something that you may well want to do. For example, let’s say that you have the following model:

   1: public class Customer

   2: {

   3:     public int Id {get;set;}

   4:     public string Name {get;set;}

   5:     public string Email {get;set;}

   6:     public string Status {get;set;

   7: }

Suppose that you would like the Name to be mandatory if the Status property is set to “New”, but if the Status property is set to “Existing” you would like the Name and the Email to be mandatory. The standard integration of FluentValidation with MVC 4 allows you to correlate a controller action’s input parameter with a validator, by decorating the model type with a Validator attribute. It will then call the Validate method on that validator at the right point by plugging in to the MVC model validation infrastructure. So far this will only allow you to run the same validation regardless of context. The validation can be further customised by adding a CustomizeValidator attribute to the model parameter on your controller action.

The CustomizeValidator attribute allows you to override the properties to validate, the rule sets to validate and an interceptor to call before and after MVC validation takes place. To take advantage of model state to apply specific validation we first need to capture our different scenarios as rule sets in the validator as follows:

   1: public class CustomerValidator : AbstractValidator

   2: {

   3:     public CustomerValidator()

   4:     {

   5:             RuleSet("New", () => {

   6:             RuleFor(c => c.Name).NotEmpty();

   7:         });

   8:

   9:         RuleSet("Existing", () => {

  10:             RuleFor(c => c.Name).NotEmpty();

  11:             RuleFor(c => c.Email).NotEmpty();

  12:         });

  13:     }

  14: }

then attribute the model class with this validator:

   1: [Validator(typeof(CustomerValidator))]

   2: public class Customer ....

Create a validation interceptor to specify the correct selector on the ValidationContext based on the model state like this:

   1: public class CustomerValidatorInterceptor : IValidatorInterceptor

   2: {

   3:     public ValidationContext BeforeMvcValidation(ControllerContext controllerContext,

   4:                 ValidationContext validationContext)

   5:     {

   6:         if (validationContext.InstanceToValidate is Customer)

   7:         {

   8:             var customer = (Customer) validationContext.InstanceToValidate;

   9:             return new ValidationContext(customer, validationContext.PropertyChain,

  10:                 new RulesetValidatorSelector(customer.Status));

  11:         }

  12:         return validationContext;

  13:     }

  14:

  15:     public ValidationResult AfterMvcValidation(ControllerContext controllerContext,

  16:                 ValidationContext validationContext,

  17:                 ValidationResult result)

  18:     {

  19:         return result;

  20:     }

  21: }

  22:

and finally add this interceptor to your controller action via the CustomizeValidation attribute like this:

   1: public ViewResult UpdateCustomer(

   2:     [CustomizeValidator(Interceptor = typeof(CustomerValidatorInterceptor))]Customer model)

   3: {

   4:     ...

   5: }

And now we will execute the correct RuleSet according to the state of the Customer object and it will all integrate with the MVC validation infrastructure nicely.

Advertisements

3 Responses

Subscribe to comments with RSS.

  1. Le Van Thong said, on March 20, 2015 at 11:12 am

    Hi you,

    How I can show message of ruleSetName in View

    • julianjelfs said, on March 20, 2015 at 11:25 am

      Sorry but I don’t really understand your question?

    • abulhasanlakhani said, on April 15, 2015 at 11:22 pm

      I don’t understand “Message of RuleSetName” but you can easily provide message for rules by using WithMessage() after RuleFor() like this

      RuleSet(“New”, () => {
      RuleFor(c => c.Name).NotEmpty().WithMessage(“Invalid!”);
      });

      RuleSet(“Existing”, () => {
      RuleFor(c => c.Name).NotEmpty().WithMessage(“Wrong!”);
      });

      So based on Model state you will either see “Invalid” or “Wrong” in the view.


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 )

Google+ photo

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

Connecting to %s

%d bloggers like this: