Being able to consistently write validation rules in a standardized way in .NET is a neccessity. This is extremely important when accepting data from boundaries out of your control such as REST APIs or gRPC.

FluentValidation solves this need by allowing you to build strongly-typed validation rules for your.NET types.

Here is an example.

example.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

public class Customer
{
    public string Surname { get; set; }
    public string Forename { get; set; }

    public int? Discount { get; set; }
    public bool HasDiscount => Discount.HasValue;

    public string Address { get; set; }
    public string PostCode { get; set; }
}

public class CustomerValidator : AbstractValidator<Customer>
{
    public CustomerValidator()
    {
        RuleFor(x => x.Surname).NotEmpty();
        RuleFor(x => x.Forename).NotEmpty().WithMessage("Please specify a first name");
        RuleFor(x => x.Discount).NotEqual(0).When(x => x.HasDiscount);
        RuleFor(x => x.Address).Length(20, 250);
        RuleFor(x => x.Postcode).Must(BeAValidPostcode).WithMessage("Please specify a valid postcode");
    }

    private bool BeAValidPostcode(string postcode)
    {
        // custom postcode validating logic goes here
    }
}

From the excellent documentation that accompanies FluentValidation:

  • instantiate the validator object
  • call the Validate method, passing in the object to validate
test.cs
1
2
3
4
5

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

ValidationResult result = validator.Validate(customer);

A simple inspection of the result IsValid property and accompanying Errors collection is all that it takes to ensure an object instance in a valid state.

We’ve barely scratched the surface here and in future blobs, I’ll share some more techniques that I like to use within my solutions.