Comment travailler avec des gestionnaires de messages dans l'API Web

Les gestionnaires de messages dans l'API Web vous offrent la possibilité de traiter, modifier ou refuser une demande entrante avant qu'elle n'atteigne le HttpControllerDispatcher. Les gestionnaires de messages sont exécutés beaucoup plus tôt dans le pipeline de traitement des demandes, ils sont donc un excellent endroit pour implémenter des préoccupations transversales dans l'API Web.

Implémentation d'un gestionnaire de messages personnalisé

Tous les gestionnaires de messages dérivent de la classe HttpMessageHandler. Pour créer votre propre gestionnaire de messages, vous devez étendre la classe DelegatingHandler. Notez que la classe DelegatingHandler dérive à son tour de la classe HttpMessageHandler.

Considérez le contrôleur d'API Web suivant.

public class DefaultController : ApiController

    {

        public HttpResponseMessage Get()

        {

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

        }

    }

Pour créer un gestionnaire de messages, vous devez étendre la classe DelegatingHandler et remplacer la méthode SendAsync.

public class Handler : DelegatingHandler

    {

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

        {

           return base.SendAsync(request, cancellationToken);

        }

    }

Le pipeline de traitement des requêtes de l'API Web comprend quelques gestionnaires de messages intégrés. Ceux-ci comprennent les éléments suivants:

  • HttpServer - il est utilisé pour récupérer la demande de l'hôte
  • HttpRoutingDispatcher - il est utilisé pour distribuer la demande en fonction de l'itinéraire configuré
  • HttpControllerDispatcher - il est utilisé pour envoyer la demande au contrôleur respectif

Vous pouvez ajouter des gestionnaires de messages au pipeline pour effectuer une ou plusieurs des opérations suivantes.

  • Effectuer l'authentification et l'autorisation
  • Journalisation des demandes entrantes et des réponses sortantes
  • Ajouter des en-têtes de réponse aux objets de réponse
  • Lire ou modifier les en-têtes de la demande

L'extrait de code suivant montre comment vous pouvez implémenter un gestionnaire de messages simple dans l'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;

        }

}

Le gestionnaire de messages ne traite pas le message de demande - il crée un message de réponse puis le renvoie. Vous pouvez également appeler la version de base de la méthode SendAsync si vous ne souhaitez rien faire avec la demande entrante, comme indiqué dans la liste de codes ci-dessous.

public class Handler : DelegatingHandler

{

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

        {

            return await base.SendAsync(request, cancellationToken);

        }

}

Vous pouvez également écrire du code pour consigner les requêtes Http et les réponses qui sortent dans la méthode SendAsync.

Pour exécuter l'API Web, vous pouvez utiliser une méthode de test comme celle donnée ci-dessous.

 [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);

        }

Lorsque vous exécutez la méthode de test, le message «À l'intérieur du contrôleur API Web par défaut ...» est renvoyé en tant que message de réponse et le test réussit. Oh! Nous avons créé un gestionnaire de messages, mais nous ne l'avons pas encore enregistré dans le pipeline de gestion des messages.

Vous devez maintenant indiquer à l'infrastructure de l'API Web où se trouve votre gestionnaire personnalisé. Pour ce faire, vous devez inscrire votre gestionnaire personnalisé dans le pipeline. Vous pouvez enregistrer le gestionnaire de messages personnalisé que nous venons de créer dans la méthode Register de la classe WebApiConfig comme indiqué ci-dessous.

public static void Register(HttpConfiguration config)

{

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

}

Lorsque vous exécutez à nouveau la méthode de test, le message texte «À l'intérieur du gestionnaire de messages de journalisation ...» est renvoyé en tant que message de réponse et le test réussit.

Notez que vous pouvez également enregistrer plusieurs gestionnaires de messages dans le pipeline de gestion des messages, comme indiqué dans l'extrait de code ci-dessous.

public static void Register(HttpConfiguration config)

{

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

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

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

}

Les gestionnaires de messages seraient exécutés dans l'ordre dans lequel ils ont été ajoutés au pipeline et la réponse serait renvoyée dans l'ordre inverse. En d'autres termes, au moment de la requête entrante, les gestionnaires de messages sont exécutés dans l'ordre dans lequel ils sont enregistrés. Lors de la réponse sortante, le processus est simplement inversé. Ainsi, les gestionnaires de messages sont exécutés dans l'ordre inverse de leur enregistrement dans le pipeline.

Vous pouvez également implémenter un gestionnaire de messages qui inspecte la demande entrante et vérifie si la demande contient une clé API valide. Si la clé API n'est pas présente ou n'est pas valide, elle renvoie un message d'erreur approprié. La liste de code suivante montre comment vous pouvez le faire - je vous laisse quand même le soin d'écrire le code pour valider la clé 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);

            }

        }