Il paradigma REST suggerisce di impostare le route dell'applicazione secondo le regole di resource discovery, dando alla forma dell'URL assegnato a una determinata risorsa un preciso significato semantico.
Una forma basilare di questo concetto si trova proprio nel pattern standard {controller}/{action}/{id} utilizzato nelle route di ASP.NET MVC fin dalle primissime versioni. Esso infatti, nella sua accezione di default, associa:
- all'URL mysite/Customers l'elenco dei customer presente in archivio;
- all'URL mysite/Customers/3 il dettaglio del customer di ID=3.
Immaginiamo però che al customer sia associato anche un elenco di ordini. Qual è l'indirizzo corretto a cui dovremmo associare questa risorsa? Con la sola route di default, l'URL che è più facilmente utilizzabile è qualcosa di simile a mySite/Orders/ByCustomer/5; tuttavia, esso viola il concetto di resource discovery, perchè, a meno del significato letterale delle parole utilizzate, non c'è alcun legame tra la nuova risorsa (gli order) e l'entità a cui appartengono (il customer).
Una soluzione sicuramente più corretta è invece costituita dall'indirizzo mySite/Customers/3/Orders, che esprime chiaramente la gerarchia di appartenenza della lista di ordini. Il problema, però, è che questo URL non è direttamente mappabile sulla route standard. Una soluzione può essere quella di definire una route personalizzata, ma il metodo più comodo è quello di sfruttare AttributeRouting e, in particolare, la funzionalità RoutePrefix.
Tramite essa, possiamo assegnare un prefisso a tutte le route associate a un determinato controller. Nel nostro caso, possiamo scrivere qualcosa di questo tipo:
[RoutePrefix("Customers/{customerId}")] public class OrdersController : Controller { [Route("Orders")] public ActionResult Orders(int customerId) { .. } }
Questa configurazione creerà una route che corrisponde esattamente alla forma che abbiamo ipotizzato. L'aspetto interessante è che possiamo definire delle componenti variabili nel prefisso, a livello di controller, e referenziarle in seguito nelle varie action. Nel nostro caso, abbiamo definito la variabile customerId, che posizionalmente precederà il token Orders, ma che comunque potremo utilizzare nella action relativa.
La stessa tecnica funziona in maniera analoga nel caso di ASP.NET Web API:
[RoutePrefix("Api/Customers/{customerId}")] public class OrdersApiController : ApiController { [Route("Orders")] public string GetOrdersByCustomer(int customerId) { return string.Format("orders for customer {0}", customerId); } }
Affinché tutto funzioni correttamente, è necessario verificare che, nei file RouteConfig.cs e WebApiConfig.cs siano invocati gli extension method necessari per attivare l'attribute routing:
public class RouteConfig { public static void RegisterRoutes(RouteCollection routes) { // ... routes.MapMvcAttributeRoutes(); } } public static class WebApiConfig { public static void Register(HttpConfiguration config) { // ... config.MapHttpAttributeRoutes(); } }
Commenti
Per inserire un commento, devi avere un account.
Fai il login e torna a questa pagina, oppure registrati alla nostra community.
Approfondimenti
Hosting di componenti WebAssembly in un'applicazione Blazor static
Utilizzare database e servizi con gli add-on di Container App
Recuperare un elemento inserito nella cache del browser tramite API JavaScript
Limitare le richieste lato server con l'interactive routing di Blazor 8
Usare le collection expression per inizializzare una lista di oggetti in C#
Inizializzare i container in Azure Container Apps
Ottimizzare il mapping di liste di tipi semplici con Entity Framework Core
Ottimizzare le performance delle collection con le classi FrozenSet e FrozenDictionary
Disabilitare automaticamente un workflow di GitHub
Mascherare l'output di un valore all'interno dei log di un workflow di GitHub
Ottenere il contenuto di una cartella FTP con la libreria FluentFTP
Verificare la provenienza di un commit tramite le GitHub Actions
I più letti di oggi
- Miglioramenti nelle performance di Angular 16
- Ottimizzare le performance delle collection con le classi FrozenSet e FrozenDictionary
- HTML5 con CSS e JavaScript
- Ottimizzazione dei block template in Angular 17
- ecco tutte le novità pubblicate sui nostri siti questa settimana: https://aspit.co/wkly buon week-end!