Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

Manipolare i messaggi HTTP

I Message handler: componenti che possono intercettare i messaggi HTTP ed eventualmente modificarli
I Message handler: componenti che possono intercettare i messaggi HTTP ed eventualmente modificarli
Link copiato negli appunti

Il flusso di messaggi HTTP scambiati tra client e server viene elaborato dal framework sfruttando l'architettura mostrata nella seguente figura:

Figura 09. (clic per ingrandire)


I messaggi HTTP che arrivano da Internet vengono acquisiti da un'istanza della classe HttpServer che crea un oggetto di tipo HttpRequestMessage e lo fa transitare attraverso uno o più componenti di tipo HttpMessageHandler. Questi hanno l'eventuale compito di intervenire sull'elaborazione del messaggio fino a raggiungere l'ultimo handler della catena rappresentato dall'HttpControllerDispatcher. Quest'ultimo ha il compito di indirizzare la richiesta HTTP al controller corretto facendo uso della tabella di routing definita per la Web API.

Il controller, a sua volta, risponde creando un oggetto di tipo HttpResponseMessage e facendolo transitare a ritroso lungo la stessa serie di componenti fino a raggiungere l'HttpServer che invierà il messaggio HTTP al client.

La descrizione del flusso dei messaggi HTTP ci è utile per comprendere il ruolo dei Message handler: si tratta di componenti che hanno la possibilità di intercettare i messaggi HTTP ed eventualmente di manipolarli in base a determinati criteri.

Per creare un Message Handler occorre definire una classe derivata da System.Net.Http.DelegatingHandler ed effettuare l'override del metodo SendAsync(). Vediamo in pratica come creare un Message handler proponendoci di implementare la verifica dell'esistenza di una chiave di autorizzazione nell'URL della richiesta. Il codice di questo Message handler è mostrato di seguito:

using System;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
namespace Glossario.MessageHandlers
{
 public class KeyValidationHandler : DelegatingHandler
 {
  protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
   CancellationToken cancellationToken)
  {
   string key;
   try
   {
    key = request.RequestUri.ParseQueryString()["key"];
   }
   catch (System.InvalidOperationException)
   {
    return Task.Factory.StartNew(() =>
    {
     return new HttpResponseMessage(HttpStatusCode.BadRequest)
     {
      Content = new StringContent("Chiave di autorizzazione mancante")
     };
    });
   }
   if (!IsValidKey(key)) {
    return Task.Factory.StartNew(() =>
     {
     return new HttpResponseMessage(HttpStatusCode.Forbidden)
     {
      Content = new StringContent("Chiave di autorizzazione non valida")
     };
    });
   }
   return base.SendAsync(request, cancellationToken);
  }
 }
}

In sintesi, l'implementazione del metodo SendAsync() tenta di individuare la chiave che il client dovrebbe passare come parametro key nell'URL di richiesta. Se la chiave non esiste, viene inviato un messaggio di risposta con codice di stato 400, Bad Request. Se invece la chiave esiste ma l'esisto della verifica della sua validità effettuata da una ipotetica funzione privata IsValidKey() ha esito negativo, verrà inviato un messaggio con codice si stato 403, Forbidden.

Se invece la chiave è valida la richiesta viene inoltrata al sistema invocando il metodo SendAsync() della classe base.

Da notare, invece, che nel caso di chiave non esistente o non valida, il nostro Message handler provvederà a creare la risposta HTTP e ad indirizzarla verso il client creando ed avviando un task tramite il metodo StartNew() di Task.Factory. Questo interrompe l'inoltro del messaggio HTTP agli eventuali altri Message handler impedendone di conseguenza l'arrivo al controller della nostra Web API.

Questo aspetto è la caratteristica fondamentale che differenzia un Message handler da un filtro, come ad esempio un Action filter o un Exception filter. Mentre l'esecuzione di un filtro avviene dopo la gestione del routing operata dall'HttpControllerDispatcher, un Message handler viene eseguito prima e può quindi avere un importante impatto sulle prestazioni della Web API evitando l'inutile inoltro di un messaggio da scartare.

Come abbiamo già visto per i filtri, anche per i Message handler occorre registrare la classe in Global.asax in corrispondenza di Application_Start():

GlobalConfiguration.Configuration.MessageHandlers.Add(new Glossario.MessageHandlers.KeyValidationHandler());

È importante sottolineare l'importanza dell'ordine di registrazione dei Message handler. Infatti esso determina l'ordine con cui i messaggi HTTP passano da un Message handler all'altro. Così, ad esempio, se abbiamo la registrazione dei seguenti handler:

GlobalConfiguration.Configuration.MessageHandlers.Add(new Glossario.MessageHandlers.Handler1());
GlobalConfiguration.Configuration.MessageHandlers.Add(new Glossario.MessageHandlers.Handler2());
GlobalConfiguration.Configuration.MessageHandlers.Add(new Glossario.MessageHandlers.Handler3());

Una richiesta HTTP verrà elaborata prima da Handler3, poi da Handler2 e quindi da Handler1. La risposta, invece, seguirà il percorso inverso partendo da Handler1 e andando verso Handler3.

Ti consigliamo anche