Tip - Fluent Validation With Null Values
[.NET, Validation, Libraries, Tips]
There is an excellent library, FluentValidation, that is very handy when it comes to expressing validation logic, and doing it centrally.
Suppose we have the following class:
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
We can express validation logic by inheriting from the generic abstract class AbstractValidator and then supplying our logic.
Like this:
public class PersonValidator : AbstractValidator<Person>
{
public PersonValidator()
{
RuleFor(x => x.Name)
.MinimumLength(5)
.MaximumLength(10);
RuleFor(x => x.Age)
.GreaterThan(18);
}
}
Our logic here is:
- Age must be greater than 18
- Name must have a length between 5 and 10 characters
Our logic to validate is as simple as this:
var person = new Person() { Name = "", Age = 30 };
var validator = new PersonValidator();
validator.ValidateAndThrow(person);
This code will throw an exception if any of the validations is not satisfied.
So the code above will throw this exception:
Validation failed:
-- Name: The length of 'Name' must be at least 5 characters. You entered 0 characters. Severity: Error
So far so good - if you provide an empty string as a name, it will throw an exception.
Suppose someone supplies a null
as the name.
Like so:
var person = new Person() { Name = null, Age = 30 };
var validator = new PersonValidator();
validator.ValidateAndThrow(person);
You’d think the logic for minimum and maximum length would catch this.
You would be wrong.
A null
will successfully pass validation!
To address this issue, you need to add an additional validation - NotEmpty()
public class PersonValidator : AbstractValidator<Person>
{
public PersonValidator()
{
RuleFor(x => x.Name)
.NotEmpty()
.MinimumLength(5)
.MaximumLength(10);
RuleFor(x => x.Age)
.GreaterThan(18);
}
}
This has the additional benefit of rejecting strings that are whitespace.
If you run the validator you should get the following result:
Validation failed:
-- Name: 'Name' must not be empty. Severity: Error
If you don’t want to throw an exception but want to get the errors anyway, you can do it like this:
var result = validator.Validate(person);
From here you can either get a dictionary of properties and errors, like this:
result.ToDictionary();
Or you can get a single string of all the errors, like this:
result.ToString();
Happy hacking!