Validare cu FluentValidation pe Commande în .NET (CreatePostCommandValidator)
Într-o arhitectură bazată pe CQRS, comanda (Command) reprezintă intenția de a modifica starea aplicației. De aceea, este esențial ca aceste comenzi să fie validate riguros înainte să ajungă la handlerul care le procesează.
În această etapă, vom integra FluentValidation pentru a valida comenzile trimise către MediatR, în mod particular CreatePostCommand.
✅ De ce FluentValidation?
-
Separarea clară a regulilor de validare de logica de business.
-
Suport complet pentru validarea obiectelor complexe.
-
Integrare automată cu IRequest<T> din MediatR.
-
Validări fluente, lizibile și extensibile.
🛠️ 1. Instalare FluentValidation
Adaugă în proiectul Application:
dotnet add package FluentValidation
dotnet add package MediatR.Extensions.Microsoft.DependencyInjection
📦 2. Creăm CreatePostCommand
public record CreatePostCommand(string Title, string Content) : IRequest<Guid>;
🧪 3. Adăugăm CreatePostCommandValidator
using FluentValidation;
public class CreatePostCommandValidator : AbstractValidator<CreatePostCommand>
{
public CreatePostCommandValidator()
{
RuleFor(x => x.Title)
.NotEmpty().WithMessage("Titlul este obligatoriu")
.MaximumLength(100).WithMessage("Titlul nu poate depăși 100 de caractere");
RuleFor(x => x.Content)
.NotEmpty().WithMessage("Conținutul este obligatoriu")
.MinimumLength(100).WithMessage("Conținutul trebuie să aibă minimum 100 de caractere");
}
}
🧩 4. Integrarea validării cu MediatR
Creează un ValidationBehavior:
public class ValidationBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
where TRequest : IRequest<TResponse>
{
private readonly IEnumerable<IValidator<TRequest>> _validators;
public ValidationBehavior(IEnumerable<IValidator<TRequest>> validators)
=> _validators = validators;
public async Task<TResponse> Handle(
TRequest request,
RequestHandlerDelegate<TResponse> next,
CancellationToken cancellationToken)
{
var context = new ValidationContext<TRequest>(request);
var failures = _validators
.Select(v => v.Validate(context))
.SelectMany(r => r.Errors)
.Where(f => f != null)
.ToList();
if (failures.Count != 0)
throw new ValidationException(failures);
return await next();
}
}
Înregistrare în DI:
services.AddValidatorsFromAssemblyContaining<CreatePostCommandValidator>();
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidationBehavior<,>));
🧪 5. Exemplu de test
var validator = new CreatePostCommandValidator();
var result = validator.Validate(new CreatePostCommand("", "Abc"));
Console.WriteLine(result.IsValid); // False
🧵 Concluzii
✅ Aplicând FluentValidation doar pe Commande, ne asigurăm că validările rigide sunt separate de citiri. Acest pattern respectă principiul Single Responsibility și pregătește terenul pentru scalare și testare.
Sunt 19 comentarii
EuCHvNFIZJkpaq JpMZFNwMlVxztL
JwrYSgHUJ PCQvLGjxO
czaUUNcBAzRII QvOqSWvw
vDWiYEPS uqvOGKUknV
ANeEacWp UFEbiyKFcySZ
PBrEQQFduikYnb EtLwuQRRxpawL
SezqsfCioJd cxxLeTjDRkyJj
qCpsxTWgyNf DqFbCUwhWNCPbJU
fnbbSGTrGzx MOshXBILRaYeik
kqYpWvqzqh WoqsvvTjfdXO
bJBSWkiF KcLuCwDhs
XJUHetPinEBLUw NXeSZjghqGDFun
gZyKOWmwxV RpkEyaDDc
zVvfKRXRnQwq RGaBIHgxt
KFndTkAg CsSVKXTGAXnrT
hmkHVqDcUR patWGctpRRmGZGl
wLIqiHxRpIqcYbc AziLxzKDxf
ZMVHdaNe UEiOqyrEQ
xoPNMclg KleDAVqCijPA