Integrare FluentValidation con CQRS e MediatR in ASP.NET Core

Introduzione

Nel precedente articolo, abbiamo esplorato come implementare il modello CQRS con MediatR in ASP.NET Core. Abbiamo creato comandi, query e gestori per separare le responsabilità di lettura e scrittura. In questo articolo, continueremo su quella base e vedremo come integrare FluentValidation per garantire che i dati siano validati correttamente prima di essere elaborati.

Cos'è FluentValidation ?

FluentValidation è una libreria .NET popolare e potente che consente di definire regole di validazione per i tuoi modelli in modo semplice e dichiarativo. Con FluentValidation, puoi separare la logica di validazione dal tuo codice principale, rendendolo più pulito e manutenibile.

Implementazione

Per cominciare, dobbiamo scaricare il codice sorgente dell’articolo precedente, che è disponibile a questo indirizzo: CQRSExample.NET su GitHub. Questo progetto contiene una configurazione di base per ASP.NET Core con CQRS e MediatR.

CQRSExample.NET

				
					git clone https://github.com/irimescucosmin/CQRSExample.NET.git

				
			

Installazione FluentValidation

Una volta scaricato il progetto e aperto con il nostro IDE preferito, possiamo procedere con l’installazione dei pacchetti NuGet necessari per l’implementazione di FluentValidation:

				
					Install-Package FluentValidation
Install-Package FluentValidation.AspNetCore

				
			

ValidationBehavior

Per evitare di richiamare i validatori all’interno del handler di ogni feature, possiamo definire una pipeline per MediatR che si occuperà di eseguire la validazione automaticamente. Questo approccio centralizza la logica di validazione e rende il codice più pulito e manutenibile.

Definisci una nuova classe ValidationBehavior che implementa IPipelineBehavior<TRequest, TResponse>

				
					using FluentValidation;
using MediatR;

namespace CQRSExample.NET.Behaviors;

public class ValidationBehavior<TRequest, TResponse>(IEnumerable<IValidator<TRequest>> validators) : IPipelineBehavior<TRequest, TResponse>
    where TRequest : IRequest<TResponse>
{

    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(result => result.Errors)
            .Where(f => f != null)
            .ToList();

        if (failures.Count != 0)
        {
            throw new ValidationException(failures);
        }

        return await next();
    }
}
				
			

Registrare ValidationBehavior e FluentValidation

Adesso che abbiamo definito il nostro ValidationBehavior, possiamo procedere con la registrazione di FluentValidation e della pipeline di validazione nel file Program.cs.

				
					
// Register MediatR
builder.Services.AddMediatR(cfg => cfg.RegisterServicesFromAssemblies(AppDomain.CurrentDomain.GetAssemblies()));

// Register FluentValidation Service
builder.Services.AddValidatorsFromAssembly(typeof(Program).Assembly);

// Register the validation behavior
builder.Services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidationBehavior<,>));
				
			

Validazione AddUserName

Ora siamo pronti per aggiungere il nostro primo validatore per il comando AddUserName. Questo garantisce che i dati siano correttamente validati prima di essere elaborati dal handler.

Creiamo una nuova classe nella cartella Features/AddUserName  che estende AbstractValidator<AddUsernameCommand> e definiamo le regole di validazione.

				
					using CQRSExample.NET.Database;
using CQRSExample.NET.Features.AddUserName;
using FluentValidation;

public class AddUsernameCommandValidator : AbstractValidator<AddUserNameCommand>
{
    public AddUsernameCommandValidator()
    {
        RuleFor(x => x.UserName).NotEmpty().WithMessage("Username is required.")
            .Must(BeUniqueUsername).WithMessage("Username already exists.");
    }

    private static bool BeUniqueUsername(string username)
    {
        return !FakeDatabase.UserNames.Contains(username);
    }
}
				
			
      • RuleFor(x => x.UserName) Specifica che la proprietà UserName del comando deve rispettare le seguenti regole:
        • NotEmpty() Assicura che il campo non sia vuoto, fornendo un messaggio di errore personalizzato.
        • Must(BeUniqueUsername) Verifica che il Username sia unico utilizzando una funzione personalizzata BeUniqueUsername, che controlla se il nome utente è già presente nel database fittizio.

Conclusione

Siamo arrivati alla fine! Ora possiamo avviare la nostra applicazione e provare le API utilizzando Swagger. Una volta avviata l’applicazione, apri il browser e visita l’URL del tuo servizio seguito da /swagger, ad esempio http://localhost:5000/swagger. Questo ti porterà all’interfaccia di Swagger, dove potrai esplorare e testare facilmente i tuoi endpoint API.

Grazie all’integrazione di FluentValidation, CQRS e MediatR, la nostra applicazione è ora robusta e ben strutturata, pronta per essere scalata e mantenuta nel tempo. Buon lavoro!

FAQ

FluentValidation è una libreria .NET per la validazione di oggetti di business. Utilizza un’API fluente per definire le regole di validazione.

CQRS (Command Query Responsibility Segregation) è un pattern architetturale che separa le operazioni di lettura (Query) dalle operazioni di scrittura (Command), migliorando la scalabilità e la manutenibilità dell’applicazione.

MediatR è una libreria .NET che implementa il pattern Mediator, permettendo la comunicazione tra componenti senza che questi siano direttamente accoppiati.

Sì, FluentValidation può essere utilizzato indipendentemente da CQRS. Può essere integrato in qualsiasi applicazione .NET per validare oggetti di business, controller MVC, e altro.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *

Skip to content