Curiosamente stamane Simone mi ha preceduto di un soffio nel parlarvi di Url Rewriting. In questi giorni infatti mi sono trovato nella necessità di soddisfare una particolare esigenza di rewriting che mi ha fatto approfondire l'argomento e avevo in mente di scrivere questo post da un po'. Preso atto che la scelta di Simone è ricaduta sull'implementazine di un IHttpModule, è evidente che il mio post non è una ripetizione perchè in realtà il metodo che ho usato è basato su una tecnica che nell'articolo di MSDN che Simone ha citato viene appena sfiorata. Eccomi quindi a proporvi il metodo che ho recentemente utilizzato per il rewriting dell'url in una applicazione che vedeva le proprie pagine riportate parzialmente nel database e parzialmente sul filesystem.

La mia implementazione di rewrite è basata sulla creazione di un HttpHandlerFactory. Se consideriamo un HttpModule come un filtro che intercetta tutte le chiamate alle pagine di una applicazione, e un HttpHandler un gestore per particolari tipi di chiamate che si sostituisce a quello delle normali pagine, la HttpHandlerFactory invece è una classe che viene usata dal runtime per istanziare un HttpHandler specifico in base alla chiamata che esso riceve. Implementando l'interfaccia IHttpHandlerFactory, in sostanza ci si pone nella HttpPipeline al livello più alto possibile e si è in grado di decidere quale handler istanziare in base all'url che si riceve ed in seguito passare ad esso la chiamata.

Questa condizione nel mio caso era davvero esemplificativa. Si trattava infatti di effettuare una semplice query nel database - query che con l'implementazione di un meccanismo di caching è diventata unica in tutta la vita dell'applicazione - e in base al risultato decidere se istanziare l'handler delle pagine aspx normalmente oppure variando leggermente l'input per ottenere oltre al rewrite, il caricamento di una specifica pagina in base a quanto specificato nel database. Vedo di spiegarmi meglio; tanto per cominciare vediamo come fa il runtime ad istanziare l'handler per le pagine aspx.

IhttpHandler page = PageParser.GetCompiledPageInstance(url, pathTranslated, context);

Per mezzo di questa semplice riga, è possibile indicare al runtime di produrre una istanza di IHttpHandler del tutto uguale a quella che produce esso stesso in condizioni normali. I parametri indicano il path virtuale, il path fisico della pagina e l'HttpContext della chiamata. Ecco quindi che in realtà utilizzando tale metodo si può "imbrogliare" il runtime facendo caricare ad esso un file che si trovi in un percorso diverso da quello reale che esso ha calcolato sulla base della chiamata. Il trucco per fare il rewriting in questo caso è di avere una singola pagina "dbpage.aspx", nella root dell'applicazione cui redirigere tutte le chiamate che fanno riferimento al database e - nel mio caso - rifilare al runtime una pagina "fisica" scelta fra una rosa di possibili layout per mezzo di un campo nel database stesso. Ecco il codice:

public IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated)
{
    PortalPage page = 
this.Indexer.FindPage(url);

    
if (page != null)
    {
        context.Items["CurrentPage"] = page;
        
return PageParser.GetCompiledPageInstance("~/dbpage.aspx", this.MapLayout(page.Layout), context);
    }

    
return PageParser.GetCompiledPageInstance(url, pathTranslated, context);
}

public string MapLayout(string layoutName)
{
    
return string.Format("~/layouts/{0}.aspx", layoutName);
}

Il codice parla da solo, ma vediamo lo stesso di spendere due parole. La prima riga reperisce l'istanza della PortalPage da un oggetto tenuto in cache, che rappresenta la struttura caricata dal database una volta per tutte. A questo punto, se la pagina viene trovata essa viene inserita nel contesto della chiamata e poi viene effettuato il rewrite modificando l'url in ~/dbpage.aspx e passando come path fisico una diversa pagina aspx - che per inciso contiene una serie di WebPartZones in un ContentPlaceHolder. Nel caso in cui la pagina non esista nel database, i parametri vengono passati così come sono ricevuti al PageParser che quindi costruirà l'IHttpHandler consueto.

Risultato di questo giochetto è che parte delle pagine dell'applicazione sono definite in una tabella del database e l'utente potrà navigare tale struttura come se fosse fusa con quella sul filesystem stesso.

Non mi rimane di segnalarvi che questa tecnica è utilizzabile anche con il framework 1.1, praticamente senza alcuna modifica.

powered by IMHO 1.3


per leggere il post originale o inviare un commento visita il seguente indirizzo: ASP.NET 2.0: Url Rewriting