Come lavorare con i gestori di messaggi nell'API Web

I gestori di messaggi nell'API Web offrono l'opportunità di elaborare, modificare o rifiutare una richiesta in arrivo prima che raggiunga HttpControllerDispatcher. I gestori di messaggi vengono eseguiti molto prima nella pipeline di elaborazione delle richieste, quindi sono un ottimo posto per implementare problemi trasversali nell'API Web.

Implementazione di un gestore di messaggi personalizzato

Tutti i gestori di messaggi derivano dalla classe HttpMessageHandler. Per creare il proprio gestore di messaggi, è necessario estendere la classe DelegatingHandler. Si noti che la classe DelegatingHandler a sua volta deriva dalla classe HttpMessageHandler.

Considera il seguente controller API Web.

public class DefaultController : ApiController

    {

        public HttpResponseMessage Get()

        {

            return Request.CreateResponse(HttpStatusCode.OK, "Inside the Default Web API Controller...");           

        }

    }

Per creare un gestore di messaggi, è necessario estendere la classe DelegatingHandler e sovrascrivere il metodo SendAsync.

public class Handler : DelegatingHandler

    {

        protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)

        {

           return base.SendAsync(request, cancellationToken);

        }

    }

La pipeline di elaborazione delle richieste API Web include alcuni gestori di messaggi incorporati. Questi includono quanto segue:

  • HttpServer: viene utilizzato per recuperare la richiesta dall'host
  • HttpRoutingDispatcher: viene utilizzato per inviare la richiesta in base alla route configurata
  • HttpControllerDispatcher: viene utilizzato per inviare la richiesta al rispettivo controller

È possibile aggiungere gestori di messaggi alla pipeline per eseguire una o più delle seguenti operazioni.

  • Eseguire autenticazione e autorizzazione
  • Registrazione delle richieste in arrivo e delle risposte in uscita
  • Aggiungi intestazioni di risposta agli oggetti di risposta
  • Leggere o modificare le intestazioni della richiesta

Il frammento di codice seguente mostra come implementare un semplice gestore di messaggi nell'API Web.

public class Handler : DelegatingHandler

{

protected async override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)

        {

            var response = new HttpResponseMessage(HttpStatusCode.OK)

            {

                Content = new StringContent("Inside the message handler...")

            };

            var task = new TaskCompletionSource();

            task.SetResult(response);

            return await task.Task;

        }

}

Il gestore dei messaggi non elabora il messaggio di richiesta: crea un messaggio di risposta e quindi lo restituisce. Puoi anche chiamare la versione base del metodo SendAsync se non desideri eseguire alcuna operazione con la richiesta in arrivo, come mostrato nell'elenco di codice seguente.

public class Handler : DelegatingHandler

{

protected async override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)

        {

            return await base.SendAsync(request, cancellationToken);

        }

}

È inoltre possibile scrivere codice per registrare le richieste Http e le risposte che escono nel metodo SendAsync.

Per eseguire l'API Web è possibile utilizzare un metodo di test come quello indicato di seguito.

 [TestMethod]

        public void WebAPIControllerTest()

        {

            HttpClient client = new HttpClient();

            var result = client.GetAsync(new Uri("//localhost//api/default/")).Result;

            string responseMessage = result.Content.ReadAsStringAsync().Result;

            Assert.IsTrue(result.IsSuccessStatusCode);

        }

Quando si esegue il metodo di test, il messaggio "Inside the Default Web API Controller ..." viene restituito come messaggio di risposta e il test viene superato. Oh! Abbiamo creato un gestore di messaggi, ma dobbiamo ancora registrarlo nella pipeline di gestione dei messaggi.

È ora necessario consentire all'infrastruttura dell'API Web di sapere dove si trova il gestore personalizzato. A tale scopo, è necessario registrare il gestore personalizzato nella pipeline. È possibile registrare il gestore di messaggi personalizzato che abbiamo appena creato nel metodo Register della classe WebApiConfig come mostrato di seguito.

public static void Register(HttpConfiguration config)

{

    GlobalConfiguration.Configuration.MessageHandlers.Add(new Handler());

}

Quando si esegue di nuovo il metodo di prova, il messaggio di testo "Inside the logging message handler ..." viene restituito come messaggio di risposta e il test viene superato.

Tieni presente che puoi anche registrare più gestori di messaggi nella pipeline di gestione dei messaggi, come mostrato nello snippet di codice riportato di seguito.

public static void Register(HttpConfiguration config)

{

    GlobalConfiguration.Configuration.MessageHandlers.Add(new MessageHandlerA());

    GlobalConfiguration.Configuration.MessageHandlers.Add(new MessageHandlerB());

    GlobalConfiguration.Configuration.MessageHandlers.Add(new MessageHandlerC());

}

I gestori di messaggi verranno eseguiti nell'ordine in cui sono stati aggiunti alla pipeline e la risposta verrà restituita nell'ordine inverso. In altre parole, al momento della richiesta in arrivo, i gestori di messaggi vengono eseguiti nell'ordine in cui sono registrati. Durante la risposta in uscita, il processo viene semplicemente invertito. Pertanto, i gestori di messaggi vengono eseguiti nell'ordine inverso rispetto alla registrazione nella pipeline.

È inoltre possibile implementare un gestore di messaggi che ispeziona la richiesta in arrivo e controlla se la richiesta contiene una chiave API valida. Se la chiave API non è presente o non è valida, restituisce un messaggio di errore appropriato. Il seguente elenco di codice mostra come puoi farlo: lascio a te scrivere il codice per convalidare comunque la chiave API.

protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)

        {

            string key = HttpUtility.ParseQueryString(request.RequestUri.Query).Get("key");

            string errorMessage = "You need to specify the api key to access the Web API.";

            try

            {

                if (!string.IsNullOrWhiteSpace(key))

                {

                    return base.SendAsync(request, cancellationToken);

                }

                else

                {

                    HttpResponseMessage response = request.CreateErrorResponse(HttpStatusCode.Forbidden, errorMessage);

                    throw new HttpResponseException(response);

                }

            }

            catch

            {

                HttpResponseMessage response = request.CreateErrorResponse(HttpStatusCode.InternalServerError, "An unexpected error occured...");

                throw new HttpResponseException(response);

            }

        }