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.
Similar to 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 WhenAsync
and UnlessAsync
versions available in case the conditional logic to call is asynchronous.
Examples
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 NotNull
.
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.