Many times, in real world applications, the input validation is not straight forward. Sometimes the validation rules may change depending on certain conditions. In this article, we are going to discuss about how to apply conditions on validation logic written using Fluent Validation.
Before we begin !
We have seen how to declare validation rules in previous posts about fluent validation. This article is going to be an extension to the previous articles. Below is the list of articles in case you want to refer them:
- Adding Fluent Validation in ASP .NET Core Web APIs
- ASP .NET Core API – Placeholders in Fluent Validation Messages
- ASP .NET Core API – Fluent Validations – Customizing Messages
- ASP .NET Core API – Fluent Validations – Collections
- ASP .NET Core API – Fluent Validators and Dependency Injection
- ASP .NET Core API – Fluent Validations – Cascade Behaviour
- Demo – Inheritance Validation using Fluent Validations
What do we need to validate ?
Let’s say we have an API to store information about customers. A customer can be an individual person or an organization. When the customer is individual person, first name and last name properties are required to be filled in. On the other hand, when the customer is an organization, the organization name needs to be filled in.
Let’s say we have a single class to represent both types of customers. The class has a Boolean property,
isOrganization. If this is set to true, it means the request contains organization’s information. Otherwise the request is supposed to contain individual’s information.
The code snippet for this type is given below. The code snippet also contains definition of the controller endpoint, which accepts this type as input parameter.
How to apply conditional validation ?
There are multiple ways in which conditions can be applied in fluent validation validators. First option is to add call to the
When method. The
When method takes an expression or a method which will return a Boolean value. If the returned value is true, then the immediately preceding validation is applied, otherwise the validation is skipped.
When, there is also an
Unless method, which takes an expression or a method as input. That expression or method should return a Boolean Value. If the returned value is false, then the immediately preceding validation is applied, otherwise the validation is skipped.
There are also
UnlessAsync versions available in case the conditional logic to call is asynchronous.
Let’s take an example. The code given below has two validators specified in a single rule. First rule checks that the value should not be null. Second validator checks that value should not be empty. And then there is a
When method call, which has condition to check that
IsOrganization should be false.
In this case, the condition specified in the
When method is applicable to the only immediate validation, which is
NotEmptyValidator. So when
IsOrganization is false, first name cannot be empty string. And regardless of value of
IsOrganization value, first name is not allowed to null.
RuleFor(x => x.FirstName) .NotNull() .NotEmpty().When(x => !x.IsOrganization)
This means that if every validation is supposed to be executed only if certain condition is satisfied, the When method should be called on every validator. In the code given above, if we want
NotNull validation to be applied only when
IsOrganization is false, then we will need to add a
When Call after
Now, if we do not want to specify same condition multiple times, then we can use top-level
When method instead of chaining the
When call after every validator. The code snippet given below shows an example of top level
When method. As we have condition only on the Boolean property which can have only two states, the alternative validations can be put inside the
Otherwise call as shown in the snippet.
We can place as many top level
When calls as needed.
I hope you find this information helpful. Let me know your thoughts.