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