Una delle funzionalità fondamentali offerte da ASP.NET Core è il routing, che consente di gestire le richieste degli utenti e indirizzarle alle rispettive azioni dei controller. Il routing è un processo cruciale per una navigazione ottimale tra le diverse pagine dell'applicazione Web. L'introduzione al routing inizia con la definizione di percorsi URL chiari e comprensibili che gli utenti possono utilizzare per accedere alle diverse sezioni dell'applicazione. Questi URL vengono mappati alle azioni dei controller, che sono i metodi responsabili di gestire le richieste degli utenti e generare le risposte appropriate.
Il routing in ASP.NET Core offre un'ampia flessibilità nella definizione di percorsi URL personalizzati, consentendo di crearne di accattivanti e significativi per migliorare l'usabilità del sito Web. E' possibile, inoltre, configurare funzionalità avanzate, come il routing a più livelli, che consente di creare URL gerarchici o di gestire sottodomini. Il routing, in pratica, offre una maggiore modularità e separazione delle responsabilità di un' applicazione Web.
Il routing in ASP.NET
Nelle scorse lezioni abbiamo esaminato come un'applicazione ASP.NET Core includa una pipeline di middleware che definisce il suo comportamento. Abbiamo visto come il middleware sia efficace per gestire sia richieste trasversali, come nel caso del logging e della gestione degli errori, che per richieste specifiche, come quelle relative alle immagini e ai file CSS.
Il routing è stato parte integrante di ASP.NET Core fin dalla sua nascita, ma in ASP.NET Core 3.0 ha subito dei grandi cambiamenti. In ASP.NET Core 2.0 e 2.1, il routing era limitato alle pagine Razor e al framework MVC di ASP.NET Core. Non c'era un middleware di routing dedicato nella pipeline dei middleware e quindi avveniva solo all'interno delle pagine Razor o dei componenti MVC. Dal momento che la maggior parte della logica dell'applicazione è implementata nelle pagine Razor, limitare il routing alle sole pagine Razor era accettabile per la maggior parte dei casi. Purtroppo, questa restrizione del routing all'infrastruttura MVC ha reso alcune cose un po' confusionarie. Significava che alcune funzionalità dell'applicazione, come l'autorizzazione, erano limitate all'infrastruttura MVC e risultavano difficili da utilizzare da altri middleware. Questa restrizione causava inevitabili duplicazioni, il che non era ideale.
In ASP.NET Core 3.0 è stato quindi introdotto un nuovo sistema di routing, chiamato endpoint routing. L'endpoint routing rende il sistema di routing una caratteristica fondamentale di ASP.NET Core perchè non lo lega più all'infrastruttura MVC. Le pagine Razor e il MVC continuano a fare affidamento sull'endpoint routing, ma ora anche altri middleware possono utilizzarlo. ASP.NET Core 5.0 utilizza lo stesso sistema di endpoint routing introdotto in ASP.NET Core 3.0.
Perchè usare il routing?
Consideriamo un'applicazione di e-commerce che vende diversi prodotti. Ogni prodotto deve avere il suo URL. Quindi se stessimo utilizzando un sistema di routing basato esclusivamente sulla disposizione dei file, avremmo solo due opzioni:
- utilizzare una pagina Razor separata per ogni prodotto nella gamma di prodotti. Questo sarebbe completamente impraticabile per quasi ogni gamma di prodotti di dimensioni realistiche.
- utilizzare una singola pagina Razor e la stringa di query per differenziare i prodotti. Questo è molto più pratico, ma si otterrebbero URL piuttosto brutti, come
/prodotto?nome=widget
o/prodotto?id=12
.
Con il routing, possiamo avere una singola pagina Razor che può gestire più URL, senza dover ricorrere a brutte stringhe di query. Ad onor del vero, le pagine Razor sono comunque capaci di visualizzare dinamicamente i risultati corretti per il prodotto appropriato ma la differenza con il routing è che con questo è possibile personalizzare completamente gli URL, offrendo molta più flessibilità, elemento chiave nelle applicazioni reali per motivi di ottimizzazione sui motori di ricerca. Nell'immagine in basso vediamo un esempio di quanto detto:
L'utilizzo dell'endpoint routing in ASP.NET Core
L'endpoint routing è fondamentale per tutte le applicazioni ASP.NET Core. Viene implementato utilizzando due componenti di middleware:
EndpointMiddleware
, utilizzato per registrare gli endpoint nel sistema di routing all'avvio dell'applicazione.EndpointRoutingMiddleware
, sceglie quale degli endpoint registrati dall'EndpointMiddleware
deve essere eseguito per una determinata richiesta durante l'esecuzione.
Per registrare gli endpoint nella nostra applicazione, ci serviamo di UseEndpoints
nel metodo Configure
del file Startup.cs
. Questo metodo accetta un'azione lambda di configurazione che definisce gli endpoint della nostra applicazione, come mostrato nel seguente esempio. Possiamo registrare automaticamente tutte le Razor Pages della nostra applicazione utilizzando estensioni come MapRazorPages
. Inoltre, possiamo registrare esplicitamente altri endpoint utilizzando metodi come MapGet
.
public void Configure(IApplicationBuilder app)
{
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
endpoints.MapHealthChecks("/healthz");
endpoints.MapGet("/test", async context =>
{
await context.Response.WriteAsync("Hello World!");
});
});
}
Nel metodo Configure
, abbiamo usato app.UseRouting()
per abilitare il routing delle richieste per la nostra applicazione. Successivamente, abbiamo utilizzato app.UseEndpoints
per definire gli endpoint dell'applicazione mediante un'azione lambda. Abbiamo registrato tutte le Razor Pages dell'applicazione utilizzando endpoints.MapRazorPages()
. Inoltre, abbiamo registrato un endpoint di health check all'indirizzo /healthz
utilizzando endpoints.MapHealthChecks()
.
Endpoint di health check
Un endpoint di health check è un endpoint all'interno di un'applicazione o di un servizio che viene utilizzato per verificare lo stato di salute dell'applicazione stessa o dei suoi componenti. È una funzionalità comune nelle applicazioni distribuite o nei servizi che vengono eseguiti in ambienti di produzione, dove è importante monitorare continuamente lo stato di salute dell'applicazione per garantire la sua disponibilità e prestazioni.
L'endpoint di health check può essere configurato per rispondere a richieste specifiche, ad esempio su un percorso URL specifico come /healthz
, e restituire una risposta che indica lo stato di salute dell'applicazione o del componente monitorato. Questa risposta può essere utilizzata dai sistemi di monitoraggio o di bilanciamento del carico per verificare che l'applicazione o il servizio sia in uno stato operativo corretto. Infine, abbiamo registrato un endpoint GET
personalizzato all'indirizzo /test
che restituisce la stringa "Hello World!" come risposta utilizzando endpoints.MapGet()
con una funzione asincrona che scrive la stringa nella risposta HTTP.
In pratica, l'EndpointMiddleware
memorizza le rotte e gli endpoint registrati in un dizionario, che condivide con il RoutingMiddleware
. Durante l'esecuzione, il RoutingMiddleware
confronta una richiesta in arrivo con le route registrate nel dizionario. Se il RoutingMiddleware
trova un endpoint corrispondente, prende nota dell'endpoint selezionato e lo collega all'oggetto HttpContext
della richiesta. Successivamente, chiama il middleware successivo nella pipeline. Quando la richiesta raggiunge l'EndpointMiddleware
, il middleware verifica quale endpoint è stato selezionato ed esegue l'azione corrispondente. Se l'URL della richiesta non corrisponde a una rotta, il RoutingMiddleware
non seleziona un endpoint, ma la richiesta continua comunque nella pipeline dei middleware.
Poiché nessun endpoint viene selezionato, l'EndpointMiddleware
ignora silenziosamente la richiesta e la passa al middleware successivo nella pipeline. L'EndpointMiddleware
è di solito l'ultimo middleware nella pipeline, quindi il "middleware successivo" è di solito un middleware fittizio che restituisce sempre una risposta 404 Not Found.
Conclusioni
In conclusione, il routing in ASP.NET Core è un'importante funzionalità che consente di indirizzare le richieste HTTP ai corrispondenti endpoint dell'applicazione. Abbiamo imparato come registrare e configurare gli endpoint utilizzando il metodo UseEndpoints
nel file Startup.cs
, e come il middleware di routing e di endpoint lavorano insieme per selezionare l'endpoint appropriato in base all'URL della richiesta.
Il routing è una parte fondamentale della creazione di API RESTful e di applicazioni Web in ASP.NET Core, consentendo di definire in modo chiaro e strutturato le URL dell'applicazione e di indirizzare le richieste ai corretti endpoint. Con una corretta configurazione del routing, è possibile creare applicazioni Web scalabili, modulari e facili da manutenere.