Impostare un constraint per una route di ASP.NET

di Marco De Sanctis, in ASP.NET 4.0, ASP.NET MVC,

Nello script #1041 abbiamo visto come utilizzare le funzionalità di URL Routing in un'applicazione Web Forms. Un aspetto importante da comprendere, però, è che il routing non è solo una nuova tecnica per scrivere gli URL in un formato più comprensibile, ma fornisce tutta una serie di funzionalità aggiuntive per la gestione di questi, tra le quali un'avanzata gestione dei parametri.

In questo ambito, riveste grande importanza la possibilità di sottoporre tali parametri ad un processo di validazione, così che possiamo essere sicuri che le nostre pagine vengano invocate solo in presenza di valori corretti. Esistono fondamentalmente due tipologie di validazione, una basata su espressioni regolari e una sull'interfaccia IRouteConstraint.

Validazione tramite espressioni regolari

Supponiamo di aver configurato una route per visualizzare i dettagli di un cliente, in modo che risponda ad un URL del tipo localhost/customer/{id}:

void Application_Start(object sender, EventArgs e)
{
  configureRoutes(RouteTable.Routes);
}

private void configureRoutes(RouteCollection routes)
{
  routes.MapPageRoute(
    "customers-id", "customers/{id}", "~/CustomerDetail.aspx");
}

Se l'identificativo del cliente è in formato numerico, è bene fare in modo che l'utente non possa invocare la pagina fornendo un valore errato, contenente ad esempio delle lettere, evitando così eventuali errori di conversione. Questo controllo può essere effettuato tramite un constraint sul routing, basato su un'espressione regolare, in modo da assicurare la presenza di sole cifre:

routes.MapPageRoute("customers-id", "customers/{id}", "~/CustomerDetail.aspx",
  false, null, new RouteValueDictionary
    (
      new { id = @"\d+" }
    )
  );

Questo overload del metodo MapPageRoute usa un RouteValueDictionary per specificare le varie regole di validazione della route; l'espressione di validazione viene associata al particolare parametro da validare tramite un anonymous type. Nel caso l'indirizzo non superi questo controllo, viene restituito un errore 404 di pagina non trovata.

Con la stessa tecnica possiamo vincolare un parametro ad un preciso subset di valori ammissibili:

routes.MapPageRoute("orders-list", "orders/{origin}", "~/Orders.aspx",
  false, null, new RouteValueDictionary
    (
      new { origin = "italia|estero"}
    )
  );

Quando però le logiche si fanno più complesse, un'espressione regolare non rappresenta lo strumento più appropriato e può essere necessario realizzare un proprio constraint personalizzato.

Utilizzo dell'interfaccia IRouteConstraint

Supponiamo che di aver realizzato una route come quella in basso, in cui l'utente può specificare la data di riferimento per la ricerca degli ordini tramite i tre parametri year, month e day:

routes.MapPageRoute(
  "orders-list", "orders/{year}/{month}/{day}", "~/OrdersByDate.aspx");

Sicuramente possiamo verificare che essi siano valori numerici, ma ciò non assicura che comunque compongano una data valida. Un controllo più accurato può essere effettuato in una classe che implementi l'interfaccia IRouteConstraint:

public class DateConstraint : IRouteConstraint
{
  public bool Match(HttpContextBase httpContext, Route route, 
    string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
  {
    try
    {
      int day = Convert.ToInt32(values["day"]);
      int month = Convert.ToInt32(values["month"]);
      int year = Convert.ToInt32(values["year"]);

      DateTime date = new DateTime(year, month, day);
      return true;
    }
    catch
    {
      return false;
    }
  }
}

Il metodo Match riceve in input diverse informazioni che possiamo utilizzare per valutare la richiesta corrente, quali ad esempio la route selezionata, l'HttpContext e i valori dei parametri. La logica per verificare la correttezza della data, in particolare, si basa sul reperimento di tre di essi e sul tentativo di costruire di un oggetto DateTime.

Nonostante questo constraint non si riferisca ad un singolo parametro, può essere comunque registrato nella route in maniera del tutto analoga ai casi precedenti:

routes.MapPageRoute(
    "orders-list", "orders/{year}/{month}/{day}", "~/OrdersByDate.aspx",
    false, null, new RouteValueDictionary(
        new
        {
            dateConstraint = new DateConstraint()
        }
    )
);

Un'ultima nota riguarda il fatto che, sebbene gli esempi che abbiamo visto siano relativi a Web Forms, sono in realtà applicabili anche alle applicazioni ASP.NET MVC. In questo caso si rendono necessari, però, alcuni minimi aggiustamenti dovuti all'utilizzo del metodo MapRoute invece di MapPageRoute.

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