Nei due script precedenti abbiamo configurato il routing di ASP.NET Core MVC sia in maniera centralizzata (https://www.aspitalia.com/script/1242/Configurare-Routing-ASP.NET-Core-MVC.aspx) che attraverso la funzionalità più puntuale dell'attribute routing (https://www.aspitalia.com/script/1243/Utilizzare-Attribute-Routing-ASP.NET-Core.aspx).
In entrambi i casi possiamo indicare dei route constraint, ovvero vincoli sul tipo e sul formato dei route parameter.
public class PersonController : Controller { //con {id:int} imponiamo che l'id debba essere //obbligatoriamente di tipo int [Route("Person/Edit/{id:int}")] public IActionResult Edit(int id) { return View(id); } }
Quando desideriamo avere un controllo ancora più preciso sulla logica del vincolo, allora è necessario realizzare un route constraint personalizzato.
Ipotizziamo che i nostri id siano codici fiscali per persone fisiche: una prima implementazione consisterebbe nel definire un vincolo basato su espressione regolare. Creiamo dunque una nuova classe chiamata CodiceFiscaleRouteConstraint e la facciamo derivare dal RegexRouteConstraint fornito con ASP.NET Core MVC.
public class CodiceFiscaleRouteConstraint : RegexRouteConstraint { //Per un'espressione regolare più accurata, vedere: //http://blog.marketto.it/2016/01/regex-validazione-codice-fiscale-con-omocodia/ const string FormatoCodiceFiscale = @"^[A-Z]{6}\d{2}[A-Z]\d{2}[A-Z]\d{3}[A-Z]$"; //Forniamo l'espressione regolare al costruttore della classe base public CodiceFiscaleRouteConstraint() : base(FormatoCodiceFiscale) { } }
Nel repository GitHub di ASP.NET Core troviamo le altre classi route constraint da cui possiamo derivare.
https://github.com/aspnet/Routing/tree/master/src/Microsoft.AspNetCore.Routing/Constraints
In questo caso, il semplice uso di un'espressione regolare non è sufficiente perché esistono altri criteri che determinano la validità di un codice fiscale, come la correttezza del suo carattere finale di controllo. Per far questo, andiamo a creare una seconda versione del nostro route constraint personalizzato che implementa l'interfaccia IRouteConstraint del namespace Microsoft.AspNetCore.Routing. Inseriamo la logica personalizzata all'interno del metodo Match.
public class CodiceFiscaleRouteConstraint : IRouteConstraint { const string FormatoCodiceFiscale = @"^[A-Z]{6}\d{2}[A-Z]\d{2}[A-Z]\d{3}[A-Z]$"; static Lazy<Regex> EspressioneCodiceFiscale = new Lazy<Regex>(() => new Regex(FormatoCodiceFiscale)); public bool Match(HttpContext httpContext, IRouter route, string routeKey, RouteValueDictionary values, RouteDirection routeDirection) { //Verifichiamo che i parametri che ci sono stati forniti non siano null. //Non è scontato, specie se sottoponiamo questo route constraint a unit testing. if (httpContext == null) throw new ArgumentNullException(nameof(httpContext)); if (route == null) throw new ArgumentNullException(nameof(route)); if (routeKey == null) throw new ArgumentNullException(nameof(routeKey)); if (values == null) throw new ArgumentNullException(nameof(values)); //Proviamo ad ottenere il valore. Potrebbe non essere stato fornito //se il route parameter era opzionale object routeValue; if (!values.TryGetValue(routeKey, out routeValue) || routeValue == null) return false; var codiceFiscale = Convert.ToString(routeValue, CultureInfo.InvariantCulture); //Finalmente verifichiamo che il codice fiscale //sia conforme alle nostre regole return VerificaFormato(codiceFiscale) && VerificaCarattereDiControllo(codiceFiscale); } private bool VerificaFormato(string codiceFiscale) { return EspressioneCodiceFiscale.Value.IsMatch(codiceFiscale); } private bool VerificaCarattereDiControllo(string codiceFiscale) { //TODO: inserire implementazione qui return true; } }
Come si vede nell'esempio, il metodo Match restituisce true quando il valore è conforme alla nostra logica di validazione.
Non resta che registrare il route constraint dal metodo ConfigureServices della classe Startup del progetto.
public void ConfigureServices(IServiceCollection services) { // Registriamo i servizi di MVC services.AddMvc(); // e poi impostiamo il route constraint indicando // un nome sintetico (cf in questo caso) services.Configure<RouteOptions>(options => options.ConstraintMap.Add("cf", typeof(CodiceFiscaleRouteConstraint)) ); }
Il nome sintetico "cf" che abbiamo fornito al metodo ConstraintMap.Add è quello da usare all'interno dei nostri route template per impostare il vincolo.
public class PersonController : Controller { //con {id:cf} imponiamo che l'id debba essere //obbligatoriamente una stringa col formato //del codice fiscale [Route("Person/Edit/{id:cf}")] public IActionResult Edit(string id) { return View(id); } }
Usare i route constraint è un buon modo per costruire regole di routing ancor più precise. Nel caso in cui l'utente inviasse richieste non conformi ai vincoli impostati, la nostra applicazione ASP.NET Core MVC risponderà con la pagina 404, proteggendo quindi le action dal ricevere dati formalmente non validi.
Commenti
Per inserire un commento, devi avere un account.
Fai il login e torna a questa pagina, oppure registrati alla nostra community.
Approfondimenti
Sfruttare lo stream rendering per le pagine statiche di Blazor 8
Utilizzare un service principal per accedere a Azure Container Registry
Sfruttare lo streaming di una chiamata Http da Blazor
Implementare il throttling in ASP.NET Core
Load test di ASP.NET Core con k6
Code scanning e advanced security con Azure DevOps
Ottimizzare il mapping di liste di tipi semplici con Entity Framework Core
Reactive form tipizzati con FormBuilder in Angular
Eseguire attività basate su eventi con Azure Container Jobs
Usare le variabili per personalizzare gli stili CSS
Gestire domini wildcard in Azure Container Apps
Utilizzare i primary constructor di C# per inizializzare le proprietà
I più letti di oggi
- annunciato #netstandard 2.1. .NET Core lo supporterà a partire da #netcore3, così come le prossime versione di #xamarin, #mono e #unity.il supporto per #netfx 4.8, invece, non ci sarà. https://aspit.co/bq2
- Annunciato Silverlight 4 RC e Windows Phone Developer Tools
- Speciale Razor: il nuovo view engine di WebMatrix e ASP.NET MVC
- Speciale Windows Store app: costruire app con WinRT per Windows 8
- Gestire lo stato all'interno di un class component di ReactJS
- Inserimenti bulk su database con la classe SqlBulkCopy di ADO.NET 2.0
- disponibile su MSDN la versione RTM di #VS2013 Update 2! https://aspit.co/auj #msTechEd