How you validate your models in your code?
How many times have you come across the typical code full of If's to validate a model?
On several occasions, working on different projects, I have encountered an abuse of if statement to perform different validations of an entity model or a Dto model.
We are talking about the typical structure as for example in c# code
if(string.IsNullOrEmpty(personDto.Name))
{
thow new Exception("Name can not be empty")
}
if(personDto.Age < 0 )
{
thow new Exception("Age range have to between 0 and 100")
}
......
Why not use other approaches in which on the one hand we have a cleaner and more maintainable code and on the other hand we avoid launching exceptions where for these cases we have a cost that has a performance cost.
We can use fantastic libraries like FluentValidation
that allows us to perform this type of validation by performing a fully declarative configuration.
In my case I've chosen as a proof of concept to create my own library inspired by FluentValidation using Builder design pattern and Expressions
领英推荐
Example of how to make a configuration to define the validation rules of a model.
internal sealed class PersonValidatorRulesSpecification : IValidatorRulesSpecification<Person> {
public IRulesValidator<Person> GetRulesValidator() {
var entityValidatorRules = RulesValidatorBuilder<Person>
.Create()
.AddRule(
ruleName: "NameStartWithJ",
condition: person => person.Name.StartsWith("j"),
failedValidationMessage: "Person Name must start with J")
.AddRule(
ruleName: "PersonLimitAge",
condition: person => person.Age > 40,
failedValidationMessage: "Age must be more than 40")
.Build();
return entityValidatorRules;
}
}
The use of this library in a console application should be
using ConsoleApp.Specifications;
using Jcc.ValidatorBuilder.Interfaces;
using Microsoft.Extensions.DependencyInjection;
var serviceProvider = new ServiceCollection()
.AddScoped<IValidatorRulesSpecification<Person>, PersonValidatorRulesSpecification>()
.BuildServiceProvider();
var service = serviceProvider
.GetService<IValidatorRulesSpecification<Person>>();
var validator = service.GetRulesValidator();
Person[] persons = [
new Person("Peter", 41, "street example"),
new Person("Pepe", 30, "street example 2"),
new Person("John", 25, "street example 3")
];
foreach (var person in persons) {
var personValidation = validator.Validate(person);
Console.WriteLine($" person with name: ${person.Name} - is valid: {personValidation.IsValid}");
foreach (var rulesErrorMessage in personValidation.FailedErrorMessages) {
Console.WriteLine($" \t rule name: {rulesErrorMessage.Key} - ruleErrorMessage: {rulesErrorMessage.Value}");
}
}
Console.Read();
------
public record Person(string Name, int Age, string Address);
You can find this example in my github account
What kind of approaches do you prefer in your model's validations?