Personalizzare il routing di ASP.NET per includere un titolo nella URL

di Marco De Sanctis, in ASP.NET 4.0,

Una delle caratteristiche in assoluto più interessanti del routing su ASP.NET è la facilità con la quale possiamo estenderne le funzionalità, modificandone il comportamento per coprire delle nostre esigenze specifiche.
Immaginiamo, ad esempio, di voler fare in modo che le pagine del nostro sito presentino un URL del formato seguente:
localhost/id_pagina/titolo-pagina.aspx
Una simile tecnica ha il pregio di rendere gli indirizzi facilmente comprensibili per gli utenti, che sono in grado di identificare immediatamente il contenuto della risorsa a cui essi puntano.

Già con l'infrastruttura standard di routing è possibile realizzare una route che supporti il pattern che abbiamo visto, sfruttando il codice in basso per introdurre i due parametri {id} e {title} nell'indirizzo:

routes.MapPageRoute(
    "article-route", "articles/{id}/{title}.aspx",
    "~/articles.aspx");

Il parametro {title} svolge una funzione "decorativa", generando quindi un URL comprensibile per soddisfare il requisito di leggibilità che ci siamo dati, mentre {id} contiene invece il vero e proprio identificativo della risorsa, e sarà effettivamente utilizzato dalla pagina per recuperare quest'ultima dal database.

Una simile soluzione, pur perfettamente funzionante, presenta un difetto insidioso in ottica SEO, che rischia di penalizzare molto il nostro sito web per ciò che concerne l'indicizzazione nei motori di ricerca: l'unico parametro utilizzato dalla pagina, di fatto, è il solo {id}, e pertanto il contenuto mostrato sarà il medesimo per qualsiasi valore di {title}. Il risultato a lungo termine è una frammentazione degli hit e delle page view su diversi indirizzi ammissibili, con conseguente diminuzione del page rank.

Per risolvere il problema, la soluzione più elegante consiste nella generazione di una route personalizzata, che chiameremo TitledRoute, in grado di riconoscere un valore errato per il parametro {title} e di effettuare un redirect permanente verso l'indirizzo corretto. Per utilizzarlo dobbiamo scrivere su global.asax del codice leggermente più complesso di quello standard, come mostrato in basso.

routes.Add(
    new TitledRoute(
        "articles/{id}/{title}.aspx",
        "title", // titleParameter
        r => ArticlesService.GetTitleById(r.Values["id"]), // checkFunction
        new PageRouteHandler("~/default.aspx")));

Il costruttore di questa route, infatti, accetta due parametri addizionali:

  • titleParameter, che indica il nome del parametro di route contenente il titolo che, come spiegato in precedenza, dovremo validare per generare eventualmente un redirect permanente;
  • checkFunction è invece un delegate, nel nostro esempio valorizzato con una lambda expression, tramite il quale possiamo restituire il valore corretto per il titolo a partire dai dati di routing; ArticleService è un ipotetico servizio in grado di interrogare la cache (o, in extremis, il database) per recuperare il titolo corrispondente all'id di ingresso.

Internamente, TitledRoute sfrutta questi due parametri all'interno del metodo GetRouteData, che viene utilizzato per determinare se la route può gestire la richesta:

public override RouteData GetRouteData(HttpContextBase httpContext)
{
    var result = base.GetRouteData(httpContext);
    
    // il risultato è != null se la route è 
    // in grado di gestire la richiesta
    if (result != null)
    {
        var actual = result.Values[titleParameter];
        var expected = checkFunction(result);
        if (!object.Equals(actual, expected))
        {
            result.Values[titleParameter] = expected;
            var newUrl = this.GetVirtualPath(
                new RequestContext(httpContext, result), result.Values);
            httpContext.Response.RedirectPermanent("~/" + newUrl.VirtualPath);
        }
    }
            
    return result;
}

Come possiamo notare, questo metodo, oltre a richiamare l'implementazione della classe base, effettua una verifica addizionale sulla corrispondenza del titolo rilevato nell'URL e il risultato restituito dall'invocazione di checkFunction. Nel caso questi non corrispondano, TitledRoute determina l'indirizzo corretto tramite il metodo GetVirtualPath, verso cui effettua poi un RedirectPermanent. Questo metodo, come abbiamo avuto già modo di vedere, restituisce uno status code 301, che indica lo spostamento definitivo della risorsa verso il nuovo indirizzo, e provoca l'aggiornamento delle tabelle di indicizzazione dei motori di ricerca.

Commenti

Visualizza/aggiungi commenti

| Condividi su: Twitter, Facebook, LinkedIn

Per inserire un commento, devi avere un account.

Fai il login e torna a questa pagina, oppure registrati alla nostra community.

Approfondimenti

I più letti di oggi