E' ormai di uso comune dare la possibilità di raggiungere le pagine di un'applicazione web attraverso URI più comprensibili per l'utente, per far riconoscere una pagina più facilmente, o ai motori di ricerca, per essere indicizzati più correttamente.
E' possibile implementare questa tecnica, conosciuta con il nome di URL rewriting, fin dalle prime versioni di ASP.NET attraverso un HTTP Module oppure, da ASP.NET 2.0, attraverso la sezione di configurazione system.web/urlMapping. Questi due mezzi non sono però mai stati ottimali per via di alcune problematiche, risolte solo con ASP.NET 2.0, riguardanti il PostBack, o per la scarsa elasticità della seconda soluzione.
Nel Service Pack 1 di ASP.NET 3.5 è presente però un nuovo assembly System.Web.Routing che contiene alcune nuovi classi, principalmente create e sfruttate da Dynamic Data e dalle applicazioni basate su MVC, che permettono di instradare le richieste su altri URI, effettuando in automatico il parsing delle variabili.
Si ponga per esempio di voler ricevere una richiesta GET su questo url, dove 1 è l'ID del prodotto:
http://miosito/products/1/descrizione%20prodotto
La richiesta in realtà sarà instradata alla pagina che mostra i prodotti, di nome products.aspx.
Per raggiungere questo scopo la nuova classe RouteTable contiene una proprietà statica Routes che permette di inserire una lista di Route che il modulo HTTP analizza per instradare le richieste. Prima di tutto bisogna quindi assicurarsi che il modulo sia installato nel web.config
<httpModules> <add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> </httpModules>
A seconda delle esigenze, nel global.asax, in un modulo HTTP o nel metodo statico AppInitialize, occorre poi popolare la collezione Routes. L'oggetto Route permette di indicare il template dell'URI, specificando tra graffe il nome della variabile e separando obbligatoriamente ogni campo da uno / (slash) o da - (trattino). Non è possibile iniziare con uno / o utilizzare il ?. Nell'esempio preso in considerazione l'URI deve essere quindi products/{idProduct}/{description}. Poiché description non è fondamentale per il funzionamento della pagina, è possibile renderlo facoltativo e dare un valore di default alla variabile, mentre alla variabile idProduct è possibile con una regex consentire un determinato input, ignorando tutte le richieste che non rispettano il vincolo. Ecco quindi il codice che inizializza l'istradamento della richiesta:
// Valori di default, se omessi l'url è comunque valido // e la variabile ha il valore di default RouteValueDictionary defaultValues = new RouteValueDictionary(); defaultValues.Add("description", ""); // Vincoli dell'uri RouteValueDictionary constraints = new RouteValueDictionary(); // Solo richiesta HTTP GET constraints.Add("httpMethod", "GET"); // Solo i numeri (regex) sono concessi come parametro idProduct constraints.Add("idProduct", @"\d+"); // Eventuali parametri aggiuntivi da portare RouteValueDictionary dataTokens = new RouteValueDictionary(); dataTokens.Add("destPath", "~/products.aspx"); // Lock in scrittura using (RouteTable.Routes.GetWriteLock()) // Preparo il route per tutta l'applicazione RouteTable.Routes.Add(new Route("products/{idProduct}/{description}", defaultValues, constraints, dataTokens, new MyRouteHandler()));
E' bene precisare che qualora una richiesta non rispetti i constraint o il template, l'utente non riceve un errore, ma un normale 404.
La classe MyRouteHandler è una classe costruita appositamente che implementa l'interfaccia IRouteHandler, richiamata dal motore di routing per ottenere il gestore effettivo della richiesta. Poiché il destinatario della richiesta è sempre la pagina products.aspx, tale implementazione non deve far altro che ottenere l'istanza della pagina, impostarne l'ID del prodotto tramite una proprietà tipizzata creata appositamente e restituirla al motore:
public class MyRouteHandler : IRouteHandler { IHttpHandler IRouteHandler.GetHttpHandler(RequestContext requestContext) { // Uso il parametro aggiuntivo per sapere la pagina di destinazione vera string virtualPath = VirtualPathUtility.ToAbsolute(requestContext.RouteData.DataTokens["destPath"].ToString()); // Dal compilatore ASP.NET ottengo la pagina vera IProductPage pp = BuildManager.CreateInstanceFromVirtualPath(virtualPath, typeof(Page)) as IProductPage; // Imposto le proprietà che servono alla pagina pp.IdProduct = Convert.ToInt32(requestContext.RouteData.Values["idProduct"]); return pp; } }
Il tipo RouteData contiene le informazioni sul match della richiesta e permette di accedere alle variabile, mentre l'interfaccia IProductPage è stata creata appositamente ed è implementata dalla pagina products.aspx, poiché dai file presenti in App_Code non è possibile "vedere" le classi delle pagine ASP.NET.
Commenti
Per inserire un commento, devi avere un account.
Fai il login e torna a questa pagina, oppure registrati alla nostra community.