Come abbiamo visto nel post precedente, ASP.NET Core 10 introduce un supporto di validazione nativo e unificato per le Minimal API, risolvendo la necessità di implementare filtri manuali o usare librerie esterne. Questo è un cambiamento fondamentale che rende le Minimal API molto più adatte agli scenari enterprise, garantendo coerenza e robustezza sin da subito.
Attivazione Semplificata
Il nuovo sistema è di tipo opt-in e si attiva in modo estremamente semplice nel file Program.cs del tuo progetto, registrando un servizio specifico:
var builder = WebApplication.CreateBuilder(args); // ✨ Abilita il supporto nativo per la validazione builder.Services.AddValidation(); // ... altri servizi var app = builder.Build(); // ... endpoint e pipeline
Una volta abilitato, il framework si occuperà automaticamente di analizzare e validare i tuoi Data Transfer Objects (DTOs) utilizzati negli handler delle Minimal API.
Copertura Unificata degli Input
La validazione automatica non è limitata solo al corpo della richiesta (JSON/XML), ma copre in modo uniforme tutti i potenziali vettori di input per un endpoint HTTP, basandosi sulle classiche Data Annotations (come [Required], [Range], [StringLength], ecc.):
- Request Bodies (Corpo della Richiesta)
- Query Parameters (Parametri nell’URL)
- Headers (Intestazioni HTTP)
Questa copertura estesa garantisce che i vincoli di business siano applicati in modo automatico prima che venga invocato il codice di logica dell’handler.
Esempi
Ecco come puoi definire i tuoi DTO e come vengono validati automaticamente dal nuovo sistema:
1. Validazione del Corpo della Richiesta (Record)
Definiamo un record per la creazione di un prodotto, utilizzando Data Annotations per i vincoli.
// 📦 DTO con vincoli di validazione
public sealed record CreaProdottoCommand(
[Required(ErrorMessage = "Il Nome è obbligatorio.")]
[StringLength(100, MinimumLength = 2, ErrorMessage = "Il Nome deve avere tra 2 e 100 caratteri.")]
string Nome,
[Range(0.01, 1000.00, ErrorMessage = "Il Prezzo deve essere tra 0,01 e 1000,00.")]
decimal Prezzo,
string? Descrizione // Campo opzionale
);
// 🌐 Endpoint Minimal API
app.MapPost("/prodotti", (CreaProdottoCommand comando) =>
{
// Se la validazione fallisce, il codice qui NON viene eseguito.
// Viene restituita in automatico una risposta 400 Bad Request.
return Results.Created($"/prodotti/{comando.Nome}", comando);
});
Se l’utente invia un payload JSON con un Nome mancante o un Prezzo negativo, l’API risponderà automaticamente con un codice HTTP 400 Bad Request contenente i dettagli del problema standardizzati (Problem Details RFC).
2. Validazione dei Parametri di Query
I vincoli si applicano anche ai parametri di query:
// 🌐 Endpoint Minimal API con parametri di query
app.MapGet("/prodotti/ricerca",
([Required] [StringLength(50)] string query, // Vincolo sulla query string
[Range(1, 100)] int page) // Vincolo sul parametro page
=>
{
// La logica di ricerca...
return Results.Ok($"Risultati per '{query}' a pagina {page}");
});
Se si tenta di chiamare GET /prodotti/ricerca?query=&page=0, la richiesta fallirà a causa della violazione dei vincoli [Required] su query e [Range] su page.
Gestione degli Errori Standardizzata
In caso di fallimento della validazione, ASP.NET Core 10 restituisce automaticamente una risposta standardizzata conforme alla specifica RFC 7807 (Problem Details), con uno stato HTTP 400 Bad Request.
Esempio di Risposta di Errore (Problem Details):
{
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"errors": {
"Nome": [
"Il Nome è obbligatorio."
],
"Prezzo": [
"Il Prezzo deve essere tra 0,01 e 1000,00."
]
}
}
Questo nuovo modello elimina la necessità di scrivere codice boilerplate per la validazione, aumentando la produttività e la sicurezza.