URL Rewriting implementing a HttpHandler |
Visits: 9411 |
Friday, May 19, 2006 |
Page not translated!
I'm sorry but the text of this page doesn't have translation at this time.
Framework .NET 2.0
Basandomi su alcuni articoli trovati in rete, ho sviluppato un personalissimo handler
HTTP per controllare le richieste dei client in modo da gestire i nomi delle pagine
in maniera dinamica. Sto parlando ovviamente del cosidetto URL Rewriting. Si tratta,
semplicemente, di utilizzare nomi di file inesistenti (ma utili) per la nostra applicazione
web.
Prendiamo come esempio il mio blog: il link
http://blog.devexperience.net/it/9/Caricare_un_file_EXE_ed_eseguirlo_in_memoria.aspx
punta ad un file inesistente sul mio server.
L'handler che ho sviluppato in pratica analizza il nome della pagina ricercata (nel
nostro caso
/it/9/Caricare_un_file_EXE_ed_eseguirlo_in_memoria.aspx) e
visualizza al visitatore, se trovata, la corrispettiva
vera pagina
(che può essere, ad esempio,
/Articolo.aspx?id=9). In questo modo Google
(ma non è il solo) apprezzerà molto di più le pagine del nostro sito che avrà anche
maggior
pagerank.
Per il mio blog ho pensato ad una struttura URL del genere:
/ [lingua] / [ID]
/ [titolo].aspx
dove, mediante l'uso delle espressioni regolari, andrò a carpire quale articolo
visualizzare al visitatore ed in quale lingua
(richiamando la pagina
Articolo.aspx?id=n). Il titolo dell'articolo viene
utilizzato solo per ricreare il nome della pagina.
I passi da seguire
Per prima cosa occorre modificare il file web.config al nodo system.web:
<httpHandlers>
<add verb="*" path="/it/*/*.aspx" type="devHttpHandler.HandleIt" />
<add verb="*" path="/en/*/*.aspx" type="devHttpHandler.HandleIt" />
</httpHandlers>
In questo modo tutte le richieste effettuate dai client a qualsiasi file
sotto
le due cartelle it e
en del mio blog, verranno redirette prima al mio handler
devHttpHandler.HandleIt
che potrà quindi controllarle ed effettuare le operazioni del caso.
Il secondo passo sarà quello di creare la classe per la verifica della richiesta
HTTP. Creiamo quindi un nuovo file HttpHandler.cs nella nostra cartella App_Code:
using System;
using System.Web;
using System.Web.UI;
using System.Globalization;
namespace devHttpHandler
{
public class HandleIt : IHttpHandlerFactory
{
public IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated)
{
// ritorno l'IHttpHanlder
// I parametri da passare sono:
// virtualPath (il path della richiesta),
// inputFile (il percorso fisico del file da richiamare),
// context (ritorno quello ricevuto al momento della richiesta)
return PageParser.GetCompiledPageInstance("/Article.aspx", context.Server.MapPath("/Article.aspx"), context);
}
public void ReleaseHandler(IHttpHandler handler)
{
}
}
}
Quando un client effettua una richiesta di pagina ASPX, il framework passa tale
richiesta alla classe
PageHandlerFactory.
Quest'ultima implementa l'interfaccia
IHttpHandlerFactory (quella che ho usato nell'esempio precedente) che possiede
2 metodi
GetHandler
e
ReleaseHandler.
Il primo metodo ci permette di gestire la chiamata HTTP utilizzando questi 4 parametri:
- context
Istanza della classe HttpContext della richiesta corrente
- requestType
Metodo di trasferimento dati HTTP (GET
o POST)
- url
L'URL della richiesta (ad es. il nostro famoso /it/9/Caricare_un_file_EXE_ed_eseguirlo_in_memoria.aspx)
- pathTranslated
Restituisce il path fisico sul server della pagina richiamata
Il metodo GetCompiledPageInstance
della classe
PageParser ci permette di restituire l'IHttpHandler della richiesta indicando
però a quale reale pagina farlo puntare (in pratica diciamo "non prendere la pagina
Caricare_un_file_EXE_ed_eseguirlo_in_memoria.aspx ma Articolo.aspx").
Fatto questo sappiamo che, digitando ad esempio /it/0/prova.aspx, il framework
reindirizzerà la richiesta del client alla classe appena implementata. Da questa
poi verrà richiamata la pagina Articolo.aspx che analizzerà l'URL della richiesta
che si comporterà di conseguenza.
La pagina Articolo.aspx
Utilizzando l'evento PreInit
della pagina, analizzo l'URL richiesto e, nel caso
di uno complesso (es. /it/9/Caricare_un_file_EXE_ed_eseguirlo_in_memoria.aspx)
visualizzo l'articolo di riferimento utilizzando l'ID trovato nel path (quel 9 infatti
è l'ID dell'articolo nel database):
protected void Page_PreInit(object sender, EventArgs e)
{
if (Request.Url.AbsoluteUri.IndexOf("/Articolo.aspx") > -1)
{
// pagina normale (es. /Articolo.aspx?id=1)
// da fare...
// controllare nel database se esiste l'articolo con questo ID
}
else
{
// pagina complessa, cerco l'ID dell'articolo nell'url
FindIdArticolo();
}
}
Il metodo
FindIdArticolo
mi permette di capire quale ID è presente nell'URL:
private void FindIdArticolo()
{
string url = Request.Url.AbsoluteUri;
Regex r = new Regex(@"/(en(glish)*|it(alian)*)/(?<id>\d+)/(?<nome>.*)\.aspx");
if (r.IsMatch(url))
{
int id = r.Match(url).Result("${id}");
// da fare...
// controllare nel database se esiste l'articolo con questo ID
}
}
A questo punto abbiamo concluso (con poche righe di codice) la generazione dinamica
di URL per il nostro sito. Google ne sarà contentissimo ;-)
Ps. Per velocizzare la scrittura di questo articolo non ho scritto molto codice
di controllo (starà a voi implementarlo), spero comunque sia utile per capirne le
basi.
|
Grazie
Stavo proprio cercando di capire come fare per implementare una cosa del genere e il tuo esempio mi calza a pennello. Molto utile. Ciao
|
| Written by miche - Wednesday, July 12, 2006 at 5:47 PM |
Io avevo fatto una cosa simile...
Ma usavo il web.config nel <urlMapping> degli add:
<urlMappings>
<add url="~/Login.aspx" mappedUrl="~/Gestione/Login.aspx"/>
<add url="~/Residenziale/Immobile.aspx" mappedUrl="~/Pagine/Residenziale.aspx"/>
<add url="~/Appartamento/Immobile.aspx" mappedUrl="~/Pagine/Appartamento.aspx"/>
... ...
|
| Written by DanKan - Tuesday, November 14, 2006 at 3:31 PM |
|
Thanks...
|
| Written by Kelly Miller - Wednesday, December 06, 2006 at 3:21 AM |
|
Ciao, ho ritenuto questo metodo semplice e veloce, ma preciso che in VB nella classe non richiama la pagina Article ma articolo e poi una domanda come mai per farla funzionare ho dovuto mettere questo simbolo ~/articolo.
CIAO GRAXIE
|
| Written by Roberto - Thursday, May 03, 2007 at 11:05 AM |
|
Il carattere ~ (Tilde) identifica la root della tua applicazione. In pratica "~/Articolo.aspx" indica la pagina "/Articolo.aspx".
Utilizzare questo carattere risulta utile quando il sito si trova in sottocartelle (come ad esempio durante il debug delle applicazioni su VS2005 o Visual Web Developer). In questi casi il web-server si avvia in una sottodirectory del tipo:
"http://localhost:0000/cartella/Default.aspx"
e richiamare la pagina "~/Default.aspx" da qualsiasi posizione del sito ti permette di evitare l'uso del path assoluto "/" che, in questo caso, ti restituirebbe un 404 pagina non trovato (perché si trova in /cartella/Default.aspx).
Ho scritto un pò in fretta.. spero sia abbastanza leggibile.. ;)
|
| Written by ZofM - Thursday, May 03, 2007 at 11:47 AM |
|
Ciao, funziona anche per normali pagine .asp o solo per .aspx?
|
| Written by Marco - Friday, July 11, 2008 at 10:02 PM |
Post new comment