Getting Started

Last updated: June 26, 2018

Installation

 

Upgrading to FluentValidation 8

If you are upgrading to FluentValidation 8 from an older version, please read the upgrade notes

Before creating any validators, you will need to add a reference to FluentValidation.dll in your project. FluentValidation is available as either a netstandard2.0 library or as a net45 library for older projects.

The simplest way to do this is to use either the NuGet package manager, or the dotnet CLI.

Using the NuGet package manager console within Visual Studio run the following command:

Install-Package FluentValidation

Or using the .net core CLI from a terminal window:

dotnet add package FluentValidation

For integration with ASP.NET Core, install the FluentValidation.AspNetCore package:

Install-Package FluentValidation.AspNetCore

For integration with legacy ASP.NET MVC 5 or WebApi 2 projects, you can use the FluentValidation.Mvc5 and FluentValidation.WebApi packages respectively.

Install-Package FluentValidation.Mvc5
Install-Package FluentValidation.WebApi

Creating your first validator

To define a set of validation rules for a particular object, you will need to create a class that inherits from AbstractValidator<T>, where T is the type of class that you wish to validate.

For example, imagine that you have a Customer class:

public class Customer {
  public int Id { get; set; }
  public string Surname { get; set; }
  public string Forename { get; set; }
  public decimal Discount { get; set; }
  public string Address { get; set; }
}

You would define a set of validation rules for this class by inheriting from AbstractValidator<Customer>:

using FluentValidation; 

public class CustomerValidator : AbstractValidator<Customer> {
}

The validation rules themselves should be defined in the validator class’s Rules method, which must be overridden.

To specify a validation rule for a particular property, call the RuleFor method, passing a lambda expression that indicates the property that you wish to validate. For example, to ensure that the Surname property is not null, the validator class would look like this:

using FluentValidation;

public class CustomerValidator : AbstractValidator<Customer> {
  public CustomerValidator() {
    RuleFor(customer => customer.Surname).NotNull();
  }
}

To run the validator, instantiate the validator object and call the Validate method, passing in the object to validate.

Customer customer = new Customer();
CustomerValidator validator = new CustomerValidator();

ValidationResult result = validator.Validate(customer);

The Validate method returns a ValidationResult object. This contains two properties:

  • IsValid - a boolean that says whether the validation suceeded.
  • Errors - a collection of ValidationFailure objects containing details about any validation failures.

The following code would write any validation failures to the console:

Customer customer = new Customer();
CustomerValidator validator = new CustomerValidator();

ValidationResult results = validator.Validate(customer);

if(! results.IsValid) {
  foreach(var failure in results.Errors) {
    Console.WriteLine("Property " + failure.PropertyName + " failed validation. Error was: " + failure.ErrorMessage);
  }
}

You can also call ToString on the ValidationResult to combine all error messages into a single string. By default, the messages will be separated with new lines, but if you want to customize this behaviour you can pass a different separator character to ToString.

ValidationResult results = validator.Validate(customer);
string allMessages = results.ToString("~");     // In this case, each message will be separated with a `~` 

Note : if there are no validation errors, ToString() will return an empty string.

Chaining validators

You can chain multiple validators together for the same property:

using FluentValidation;

public class CustomerValidator : AbstractValidator<Customer> {
  public CustomerValidator() 
    RuleFor(customer => customer.Surname).NotNull().NotEqual("foo");
  }
}

This would ensure that the surname is not null and is not equal to the string ‘foo’.

Throwing Exceptions

Instead of returning a ValidationResult, you can alternatively tell FluentValidation to throw an exception if validation fails by using the ValidateAndThrow method:

Customer customer = new Customer();
CustomerValidator validator = new CustomerValidator();

validator.ValidateAndThrow(customer);

This throws a ValidationException which contains the error messages in the Errors property.

Note ValidateAndThrow is an extension method, so you must have the FluentValidation namespace imported with a using statement at the top of your file in order for this method to be available.

using FluentValidation;

Collections

You can use the RuleForEach method to apply the same rule to multiple items in a collection:

public class Person {
  public List<string> AddressLines {get;set;} = new List<string>();
}
public class PersonValidator : AbstractValidator<Person> {
  public PersonValidator() {
    RuleForEach(x => x.AddressLines).NotNull();
  }
}

The above rule will run a NotNull check against each item in the AddressLines collection.

You can optionally include or exclude certain items in the collection from being validated by using the Where method. Note this must come directly after the call to RuleForEach:

RuleForEach(x => x.Orders)
  .Where(x => x.Cost != null)
  .SetValidator(new OrderValidator());

Complex Properties

Validators can be re-used for complex properties. For example, imagine you have two classes, Customer and Address:

public class Customer {
  public string Name { get; set; }
  public Address Address { get; set; }
}

public class Address {
  public string Line1 { get; set; }
  public string Line2 { get; set; }
  public string Town { get; set; }
  public string County { get; set; }
  public string Postcode { get; set; }
}

… and you define an AddressValidator:

public class AddressValidator : AbstractValidator<Address> {
  public AddressValidator() {
    RuleFor(address => address.Postcode).NotNull();
    //etc
  }
}

… you can then re-use the AddressValidator in the CustomerValidator definition:

public class CustomerValidator : AbstractValidator<Customer> {
  public CustomerValidator() {
    RuleFor(customer => customer.Name).NotNull();
    RuleFor(customer => customer.Address).SetValidator(new AddressValidator());
  }
} 

… so when you call Validate on the CustomerValidator it will run through the validators defined in both the CustomerValidator and the AddressValidator and combine the results into a single ValidationResult.

If the child property is null, then the child validator will not be executed.

Instead of using a child validator, you can define child rules inline, eg:

RuleFor(customer => customer.Address.PostCode).NotNull()

In this case, a null check will not be performed automatically on Address, so you should explicitly add a condition

RuleFor(customer => customer.Address.PostCode).NotNull().When(customer => customer.Address != null)

RuleSets

RuleSets allow you to group validation rules together which can be executed together as a group whilst ignoring other rules:

For example, let’s imagine we have 3 properties on a Person object (Id, Surname and Forename) and have a validation rule for each. We could group the Surname and Forename rules together in a “Names” RuleSet:

 public class PersonValidator : AbstractValidator<Person> {
  public PersonValidator() {
     RuleSet("Names", () => {
        RuleFor(x => x.Surname).NotNull();
        RuleFor(x => x.Forename).NotNull();
     });
 
     RuleFor(x => x.Id).NotEqual(0);
  }
}

Here the two rules on Surname and Forename are grouped together in a “Names” RuleSet. We can invoke only these rules by passing a ruleSet parameter to the Validate extension method (note that this must be a named parameter as this overload has several options available).

var validator = new PersonValidator();
var person = new Person();
var result = validator.Validate(person, ruleSet: "Names");

This allows you to break down a complex validator definition into smaller segments that can be executed in isolation. If you call Validate without passing a ruleset then only rules not in a RuleSet will be executed.

You can execute multiple rulesets by using a comma-separated list of strings:

validator.Validate(person, ruleSet: "Names,MyRuleSet,SomeOtherRuleSet")

…and you can also include rules not in any ruleset by specifying a ruleset of “default”:

validator.Validate(person, ruleSet: "default,MyRuleSet")

This would execute rules in the MyRuleSet set, and those rules not in any ruleset.

You can force all rules to be executed regardless of whether or not they’re in a ruleset by specifying a ruleset of “*”:

validator.Validate(person, ruleSet: "*")

Note The Validate method that takes a ruleset is an extension method so you must have the FluentValidation namespace imported with a using statment in order to use it.

Including Rules

You can include rules from other validators provided they validate the same type. This allows you to split rules across multiple classes and compose them together (in a similar way to how other languages support traits). For example, imagine you have 2 validators that validate different aspects of a Person:

public class PersonAgeValidator : AbstractValidator<Person>  {
  public PersonAgeValidator() {
    RuleFor(x => x.DateOfBirth).Must(BeOver18);
  }

  protected bool BeOver18(DateTime date) {
    //...
  }
}

public class PersonNameValidator : AbstractValidator<Person> {
  public PersonNameValidator() {
    RuleFor(x => x.Surname).NotNull().Length(0, 255);
    RuleFor(x => x.Forename).NotNull().Length(0, 255);
  }
}

Because both of these validators are targetting the same model type (Person), you can combine them using Include:

public class PersonValidator : AbstractValidator<Person> {
  public PersonValidator() {
    Include(new PersonAgeValidator());
    Include(new PersonNameValidator());
  }
}

Note: You can only include validators that target the same type as the root validator.

Configuring

Overriding the Message

You can override the default error message for a validator by calling the WithMessage method on a validator definition:

RuleFor(customer => customer.Surname).NotNull().WithMessage("Please ensure that you have entered your Surname");

Note that custom error messages can contain placeholders for special values such as ‘{PropertyName}’ - which will be replaced in this example with the name of the property being validated. This means the above error message could be re-written as:

RuleFor(customer => customer.Surname).NotNull().WithMessage("Please ensure you have entered your {PropertyName}");

…and the value ‘Surname’ will be inserted.

Configuring Error Message Parameters (Placeholders)

As specified in the example above, the message can contain placeholders for special values such as ‘{PropertyName}’ - which will be replaced with a specified value. Each type of built-in validator has its own list of placeholders which are supported by it.

The placeholders are: Used in all validators:

  • ‘{PropertyName}’ - The name of the property being validated
  • ‘{PropertyValue}’ - The value of the property being validated These include the predicate validator (‘Must’ validator), the email and the regex validators.

Used in comparison validators: (Equal, NotEqual, GreaterThan, GreaterThanOrEqual, etc.)

  • {ComparisonValue} = Value that the property should be compared to

Used only in the Length validator:

  • {MinLength} = Minimum length
  • {MaxLength} = Maximum length
  • {TotalLength} = Number of characters entered

For a complete list of error message placeholders see the the Built in Validators page. Each built in validator has its own supported placeholders.

It is also possible to use your own custom arguments in the validation message. These can either be static values or references to other properties on the object being validated. This can be done by using the overload of WithMessage that takes a lambda expression, and then passing the values to string.Format or by using string interpolation.

//Using static values in a custom message:
RuleFor(customer => x.Surname).NotNull().WithMessage(customer => string.Format("This message references some constant values: {0} {1}", "hello", 5));
//Result would be "This message references some constant values: hello 5"

//Referencing other property values:
RuleFor(customer => customer.Surname)
  .NotNull()
  .WithMessage(customer => $"This message references some other properties: Forename: {customer.Forename} Discount: {customer.Discount}");
//Result would be: "This message references some other properties: Forename: Jeremy Discount: 100"

If you want to override all of FluentValidation’s default error messages, check out FluentValidation’s support for Localization.

Overriding the Property Name

The default validation error messages contain the property name being validated. For example, if you were to define a validator like this:

RuleFor(customer => customer.Surname).NotNull();

…then the default error message would be ‘Surname’ must not be empty. Although you can override the entire error message by calling WithMessage, you can also replace just the property name by calling WithName:

RuleFor(customer => customer.Surname).NotNull().WithName("Last name");

Now the error message would be ‘Last name’ must not be empty.

Note that this only replaces the name of the property in the error message. When you inspect the Errors collection on the ValidationResult, this error will still be associated with a property called Surname. If you want to completely rename the property, you can use the OverridePropertyName method instead.

There is also an overload of WithName that accepts a lambda expression in a similar way to WithName in the above example

Property name resolution is also pluggable. By default, the name of the property extracted from the MemberExpression passed to RuleFor. If you want change this logic, you can set the DisplayNameResolver property on the ValidatorOptions class:

ValidatorOptions.DisplayNameResolver = (type, member) => {
  if(member != null) {
     return member.Name + "Foo";
  }
  return null;
};

This is not a realistic example as it changes all properties to have the suffix “Foo”, but hopefully illustrates the point.

Additionally, FluentValidation will respect the use of the DisplayName and Display attributes for generating the property’s name within error messages:

public class Person {
  [Display(Name="Last name")]
  public string Surname { get; set; }
}

Conditions

The When and Unless methods can be used to specify conditions that control when the rule should execute. For example, this rule on the CustomerDiscount property will only execute when IsPreferredCustomer is true:

RuleFor(customer => customer.CustomerDiscount).GreaterThan(0).When(customer => customer.IsPreferredCustomer);

The Unless method is simply the opposite of When.

If you need to specify the same condition for multiple rules then you can call the top-level When method instead of chaining the When call at the end of the rule:

When(customer => customer.IsPreferred, () => {
   RuleFor(customer => customer.CustomerDiscount).GreaterThan(0);
   RuleFor(customer => customer.CreditCardNumber).NotNull();
});

This time, the condition will be applied to both rules.

Setting the Cascade mode

You can set the cascade mode to customise how FluentValidation executes chained validators when a particular validator in the chain fails.

Imagine you have two validators defined as part of a single rule definition, a NotNull validator and a NotEqual validator:

RuleFor(x => x.Surname).NotNull().NotEqual("foo");

This will first check whether the Surname property is not null and then will check if it’s not equal to the string “foo”. If the first validator (NotNull) fails, then the call to NotEqual will still be invoked. This can be changed by specifying a cascade mode of StopOnFirstFailure:

RuleFor(x => x.Surname).Cascade(CascadeMode.StopOnFirstFailure).NotNull().NotEqual("foo");

Now, if the NotNull validator fails then the NotEqual validator will not be executed. This is particularly useful if you have a complex chain where each validator depends on the previous validator to succeed.

The two cascade modes are:

  • Continue (the default) - always invokes all validators in a rule definition
  • StopOnFirstFailure - stops executing a rule as soon as a validator fails

As well as being set at the rule level, the cascade mode can also be set globally for all validators, or for all the rules in a particular validator class.

To set the cascade mode globally, you can set the CascadeMode property on the static ValidatorOptions class during your application’s startup routine:

ValidatorOptions.CascadeMode = CascadeMode.StopOnFirstFailure;

This can then be overridden by individual validator classes or by individual rules.

To set the cascade mode for all rules inside a single validator class, set the CascadeMode property on AbstractValidator:

public class PersonValidator : AbstractValidator<Person> {
  public PersonValidator() {
    // First set the cascade mode
    CascadeMode = CascadeMode.StopOnFirstFailure;

    RuleFor(...)
    RuleFor(...)
  }
}

Dependent Rules

By default, all rules in FluentValidation are separate and cannot influence one another. This is intentional and necessary for asynchronous validation to work. However, there may be some cases where you want to ensure that some rules are only executed after another has completed. You can use DependentRules to do this.

To use DependentRules, call the DependentRules method at the end of the rule that you want others to depend on. This method accepts a lambda expression inside which you can define other rules that will be executed only if the first rule passes:

RuleFor(x => x.Surname).NotNull().DependentRules(() => {
  RuleFor(x => x.Forename).NotNull();
});

Here the rule against Forename will only be run if the Surname rule passes.

Jeremy’s note: Personally I do not particularly like using DependentRules as I feel it’s fairly hard to read, especially with a complex set of rules. In many cases, it can be simpler to use When conditions to prevent rules from running in certain situations. Even though this can sometimes mean more duplication, it is often easier to read.

Root Context Data

For advanced users, it’s possible to pass arbitrary data into the validation pipeline that can be accessed from within custom property validators. This is particularly useful if you need to make a conditional decision based on arbitrary data not available within the object being validated, as validators are stateless.

The RootContextData property is a Dictionary<string, object> available on the ValidationContext.:

var instanceToValidate = new Person();
var context = new ValidationContext<Person>(person);
context.RootContextData["MyCustomData"] = "Test";
var validator = new PersonValidator();
validator.Validate(context);

The RootContextData can then be accessed inside any custom property validators, as well as calls to Custom:

RuleFor(x => x.Surname).Custom((x, context) => {
  if(context.ParentContext.RootContextData.ContainsKey("MyCustomData")) {
    context.AddFailure("My error message");
  }
});

Using PreValidate

If you need to run specific code every time a validator is invoked, you can do this by overriding the PreValidate method. This method takes a ValidationContext as well as a ValidationResult, which you can use to customise the validation process.

The method should return true if validation should continue, or false to immediately abort. Any modifications that you made to the ValidationResult will be returned to the user.

Note that this method is called before FluentValidation performs its standard null-check against the model being validated, so you can use this to generate an error if the whole model is null, rather than relying on FluentValidation’s standard behaviour in this case (which is to throw an exception):

public class MyValidator : AbstractValidator<Person> {
  public MyValidator() {
    RuleFor(x => x.Name).NotNull();
  }

  protected override bool PreValidate(ValidationContext<Person> context, ValidationResult result) {
    if (context.InstanceToValidate == null) {
      result.Errors.Add(new ValidationFailure("", "Please ensure a model was supplied."));
      return false;
    }
    return true;
  }
}

Callbacks

You can make use of the OnAnyFailure and OnFailure (as of 8.0) callbacks to run a method if validation fails.

OnAnyFailure will be invoked if there are any failures within a rule chain:

RuleFor(x => x.Surname).NotNull().Must(surname => surname != null && surname.Length <= 200)
  .OnAnyFailure(x => {
    Console.WriteLine("At least one validator in this rule failed");
  })

OnFailure will be invoked for each validator that fails:

RuleFor(x => x.Surname).NotNull().OnFailure(x => Console.WriteLine("Nonull failed"))
  .Must(surname => surname != null && surname.Length <= 200)
  .OnAnyFailure(x => Console.WriteLine("Must failed"));