URL Rewriting implementing a HttpHandler |
Visite: 12618 |
venerdì 19 maggio 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
|
| Scritto da miche - mercoledì 12 luglio 2006 alle ore 17.47 |
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"/>
... ...
|
| Scritto da DanKan - martedì 14 novembre 2006 alle ore 15.31 |
|
Thanks...
|
| Scritto da Kelly Miller - mercoledì 6 dicembre 2006 alle ore 3.21 |
|
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
|
| Scritto da Roberto - giovedì 3 maggio 2007 alle ore 11.05 |
|
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.. ;)
|
| Scritto da ZofM - giovedì 3 maggio 2007 alle ore 11.47 |
|
Ciao, funziona anche per normali pagine .asp o solo per .aspx?
|
| Scritto da Marco - venerdì 11 luglio 2008 alle ore 22.02 |
|
Non è possibile fare altrettanto con risorse fittizie html? Ad esempio
/it/9/Caricare_un_file_EXE_ed_eseguirlo_in_memoria.html
Ho provato a sostituire l'estensione nell'Handler del web.config in questo modo
ma non funziona.
Grazie in anticipo
|
| Scritto da Nicola - martedì 27 gennaio 2009 alle ore 18.26 |
@Nicola
Non è possibile fare altrettanto con risorse fittizie html? Ad esempio /it/9/Caricare_un_file_EXE_ed_eseguirlo_in_memoria.html Ho provato a sostituire l'estensione nell'Handler del web.config in questo modo ma non funziona.
Si, certo.. ma è necessario mappare l'estensione .HTML su IIS altrimenti questi file verranno considerati sempre come statici. Attenzione però: una volta mappati, verranno sempre eseguiti dall'isapi .net, quindi se si tenterà di aprire un vero file .html, esso andrà in errore, proprio come se fosse una pagina aspx mal scritta.
|
| Scritto da ZofM - mercoledì 28 gennaio 2009 alle ore 8.42 |
|
Ciao,
sto cercando di convertire il tuo UrlRewriting in VB.NET, purtroppo ricevo errore alla riga Implements IHttpHandlerFactory e l'errore è: "BC30149: Class 'HandleIt' deve implementare 'Function GetHandler(context As HttpContext, requestType As String, url As String, pathTranslated As String) As IHttpHandler' per l'interfaccia 'System.Web.IHttpHandlerFactory'."
|
| Scritto da Fabio - sabato 21 marzo 2009 alle ore 0.11 |
Ciao, purtroppo non conosco benissimo VB ma hai già provato una cosa del genere?
Public Overridable Function GetHandler (context As HttpContext, requestType As String, url As String, pathTranslated As String) As IHttpHandler Implements IHttpHandlerFactory.GetHandle
?
|
| Scritto da ZofM - sabato 21 marzo 2009 alle ore 11.30 |
|
Ciao,
ho provato il tuo script in locale ottengo pagina non trovata
in remoto:
Security Exception
The application attempted to perform an operation not allowed by the security policy.
qualche idea?
|
| Scritto da Daniele - venerdì 28 agosto 2009 alle ore 14.02 |
Scrivi nuovo commento