Comment implémenter un DelegatingHandler pour X-HTTP-Method-Override dans l'API Web

Lors du déploiement de votre API Web REST sur un domaine public, vous rencontrerez parfois des problèmes liés à la prise en charge des verbes HTTP. Les deux défis à cet égard sont la prise en charge limitée des verbes HTTP dans les anciens navigateurs Web (c'est-à-dire qu'ils ne prennent en charge que HTTP GET et HTTP POST) et les pare-feu agressifs qui bloquent le trafic qui n'est ni HTTP GET ni HTTP POST. Comment votre application prendra-t-elle en charge un PUT ou DELETE dans ces cas? Voici exactement où l'en-tête HTTP X-HTTP-Method-Override vient à la rescousse.

L'en-tête HTTP X-HTTP-Method-Override fonctionne un peu comme un hack. Vous pouvez ajouter l'en-tête avec la valeur PUT ou DELETE lors de l'appel de votre API Web via JavaScript ou via un XMLHttpRequestobjet à partir d'un navigateur Web à l'aide d'un appel HTTP POST. Vous pouvez alors demander à un gestionnaire de délégation d'intercepter la méthode HTTP à appeler et d'effectuer les actions appropriées.

Dans cet article, je vais expliquer comment nous pouvons utiliser un gestionnaire de délégation devant le pipeline demande-réponse pour modifier la demande d'envoyer un message valide à notre application, ou modifier la réponse pour renvoyer une réponse valide au client.

Verbes HTTP et gestionnaires de délégation

Si nous sommes contraints d'utiliser uniquement les verbes HTTP GET et POST en raison de limitations imposées par votre client, le navigateur Web ou le pare-feu de votre application Web, nous devrons implémenter une solution de contournement pour prendre en charge PUT et DELETE. Cette solution de contournement implique généralement l'ajout de l'en-tête HTTP X-HTTP-Method-Override à la demande qui spécifie le verbe que nous voulons utiliser dans l'appel HTTP POST. De plus, nous avons besoin d'un gestionnaire de délégation dans notre application qui vérifie l'en-tête et, s'il existe, effectue l'appel à la méthode HTTP que vous souhaitez invoquer.

Avant de plonger dans l'implémentation, jetons un coup d'œil à ce que sont les gestionnaires de délégation et pourquoi nous en utiliserions un ici. Un gestionnaire de délégation et d'autres gestionnaires de messages sont exécutés au début du pipeline de traitement des demandes. Ce sont des classes qui acceptent les requêtes HTTP et renvoient une réponse HTTP. Les gestionnaires de délégation sont similaires à HttpModulesASP.Net. Mais contrairement à HttpModules, les gestionnaires de délégation peuvent être chaînés: un gestionnaire de délégation peut référencer un autre gestionnaire de délégation. Pour en savoir plus sur la délégation de gestionnaires, consultez mon article précédent, «Comment utiliser les gestionnaires de messages dans l'API Web».

Créer un contrôleur d'API Web

Supposons que vous disposez d'un contrôleur d'API Web similaire à celui-ci:

public class AuthorsController: ApiController

    {

        // GET: api / auteurs

        public IEnumerable Get ()

        {

            retourne une nouvelle chaîne [] {"Joydip", "Kanjilal"};

        }

        // GET: api / auteurs / 1

        chaîne publique Get (int id)

        {

            retourne «Joydip Kanjilal»;

        }

        // POST api / auteur

        Public void Post ([FromBody] Author value) {}

        // PUT api / auteur / 1

        public void Put (int id, [FromBody] Author value) {}

        // SUPPRIMER api / author / 1

        public void Delete (int id) {}

    }

Créer un DelegatingHandler pour X-HTTP-Method-Override

Maintenant, implémentons un gestionnaire X-HTTP-Method-Override. Il s'agit d'un gestionnaire de messages, donc comme d'habitude, il devrait étendre la DelegatingHandlerclasse.

public class CustomMessageHandler: DelegatingHandler

    {

        readonly string [] httpMethodsList = {"DELETE", "HEAD", "PUT"};

        const string httpMethodOverrideheader;

        Tâche de remplacement protégé SendAsync (requête HttpRequestMessage, CancellationToken cancelToken)

        {

            if (request.Method == HttpMethod.Post && request.Headers.Contains (httpMethodOverrideheader))

            {               

                var httpMethod = request.Headers.GetValues ​​(httpMethodOverrideheader) .FirstOrDefault ();

                if (httpMethodsList.Contains (httpMethod, StringComparer.InvariantCultureIgnoreCase))

                {                  

                    request.Method = new HttpMethod (httpMethod);

                }

            }

            return base.SendAsync (demande, annulationToken);

        }

    }

Le code est assez explicite. Il recherche un HTTP POST ayant l'en-tête X-HTTP-Method-Override. Si l'en-tête est dans la liste des méthodes, la méthode de requête est modifiée.

Enregistrer le DelegatingHandler

L'étape suivante consiste à enregistrer le gestionnaire. Vous pouvez le faire en ajoutant ce nouveau gestionnaire à la collection MessageHandlers dans la classe WebApiConfig, comme indiqué dans l'extrait de code ci-dessous.

Registre public static void (configuration HttpConfiguration)

{

    config.MessageHandlers.Add (new CustomMessageHandler ());

     // Routes API Web

    config.MapHttpAttributeRoutes ();

     config.Routes.MapHttpRoute (

        nom: "DefaultApi",

        routeTemplate: "api / {controller} / {id}",

        par défaut: new {id = RouteParameter.Optional}

    );

}

Vous pouvez également inscrire le gestionnaire de délégation à l'aide du Application_Startgestionnaire d'événements dans le fichier Global.asax.cs comme indiqué ci-dessous.

protected void Application_Start (expéditeur de l'objet, EventArgs e)

        {

            RegisterRoutes (RouteTable.Routes);

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

        }

C'est tout ce que vous avez à faire côté serveur. Du côté client, c'est-à-dire à partir du navigateur Web, vous devez vous assurer d'ajouter l'en-tête de remplacement comme indiqué dans l'extrait de code ci-dessous.

$ .ajax ({

  url: "// localhost: 9820 / api / Authors / 1",

  tapez: "POST",

  données: JSON.stringify (authorData),

  en-têtes: {

      "Content-Type": "application / json",

      "X-HTTP-Method-Override": "PUT"},

})

Comme vous pouvez le voir dans l'extrait de code précédent, tout ce que vous avez à faire est de spécifier la méthode HTTP que vous souhaitez appeler dans l'en-tête de la requête - X-HTTP-Method-Override : DELETEou X-HTTP-Method-Override : PUT-, puis de faire un appel POST à ​​votre ressource.