Come implementare un DelegatingHandler per X-HTTP-Method-Override nell'API Web

Quando si distribuisce l'API Web REST su un dominio pubblico, a volte si riscontrano problemi relativi al supporto per i verbi HTTP. Le due sfide a questo proposito sono il supporto limitato per i verbi HTTP nei vecchi browser web (cioè supportano solo HTTP GET e HTTP POST) e firewall aggressivi che bloccano il traffico che non è né un HTTP GET né un HTTP POST. In che modo la tua applicazione supporterà un PUT o DELETE in questi casi? Ecco esattamente dove viene in soccorso l'intestazione HTTP X-HTTP-Method-Override.

L'intestazione HTTP X-HTTP-Method-Override funziona in qualche modo simile a un hack. È possibile aggiungere l'intestazione con un valore PUT o DELETE quando si richiama l'API Web tramite JavaScript o tramite un XMLHttpRequestoggetto da un browser Web utilizzando una chiamata HTTP POST. È quindi possibile fare in modo che un gestore di delega intercetti il ​​metodo HTTP da richiamare e intraprenda le azioni appropriate.

In questo articolo discuterò come possiamo utilizzare un gestore di delega davanti alla pipeline di richiesta-risposta per modificare la richiesta di inviare un messaggio valido alla nostra applicazione, o alterare la risposta per restituire una risposta valida al client.

Verbi HTTP e gestori di delega

Se siamo costretti a utilizzare solo i verbi HTTP GET e POST a causa delle limitazioni imposte dal tuo client, dal browser web o dal firewall che si affaccia sulla tua applicazione web, dovremo implementare una soluzione alternativa per supportare PUT e DELETE. Questa soluzione alternativa comporta in genere l'aggiunta dell'intestazione HTTP X-HTTP-Method-Override alla richiesta che specifica il verbo che si desidera utilizzare all'interno della chiamata HTTP POST. Inoltre, abbiamo bisogno di un gestore di delega nella nostra applicazione che controlli l'intestazione e, se esiste, effettui la chiamata al metodo HTTP che desideri venga invocato.

Prima di immergerci nell'implementazione, diamo una rapida occhiata a cosa sono i gestori di delega e perché dovremmo usarne uno qui. Un gestore di delega e altri gestori di messaggi vengono eseguiti all'inizio della pipeline di elaborazione delle richieste. Queste sono classi che accettano richieste HTTP e restituiscono una risposta HTTP. I gestori delegati sono simili a quelli di HttpModulesASP.Net. Ma a differenza dei HttpModulesgestori di delega possono essere concatenati: un gestore di delega può fare riferimento a un altro gestore di delega. Puoi saperne di più sulla delega dei gestori dal mio precedente articolo, "Come lavorare con i gestori di messaggi nell'API Web".

Crea un controller API Web

Supponi di avere un controller API Web simile a questo:

classe pubblica AuthorsController: ApiController

    {

        // GET: api / autori

        public IEnumerable Get ()

        {

            restituisce una nuova stringa [] {"Joydip", "Kanjilal"};

        }

        // GET: api / autori / 1

        stringa pubblica Get (int id)

        {

            restituire "Joydip Kanjilal";

        }

        // POST api / author

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

        // PUT api / author / 1

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

        // DELETE api / author / 1

        public void Delete (int id) {}

    }

Crea un DelegatingHandler per X-HTTP-Method-Override

Ora implementiamo un gestore X-HTTP-Method-Override. Questo è un gestore di messaggi, quindi come al solito dovrebbe estendere la DelegatingHandlerclasse.

classe pubblica CustomMessageHandler: DelegatingHandler

    {

        stringa di sola lettura [] httpMethodsList = {"DELETE", "HEAD", "PUT"};

        const string httpMethodOverrideheader;

        protected override Task SendAsync (richiesta 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 (request, cancelToken);

        }

    }

Il codice è abbastanza autoesplicativo. Verifica la presenza di un POST HTTP con l'intestazione X-HTTP-Method-Override. Se l'intestazione è nell'elenco dei metodi, il metodo di richiesta viene modificato.

Registrare il DelegatingHandler

Il passaggio successivo consiste nel registrare il gestore. Puoi farlo aggiungendo questo nuovo gestore alla raccolta MessageHandlers nella classe WebApiConfig come mostrato nello snippet di codice di seguito.

registro void statico pubblico (configurazione HttpConfiguration)

{

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

     // Percorsi API Web

    config.MapHttpAttributeRoutes ();

     config.Routes.MapHttpRoute (

        nome: "DefaultApi",

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

        valori predefiniti: new {id = RouteParameter.Optional}

    );

}

In alternativa, è possibile registrare il gestore di delega utilizzando il Application_Startgestore eventi nel file Global.asax.cs come mostrato di seguito.

protected void Application_Start (oggetto mittente, EventArgs e)

        {

            RegisterRoutes (RouteTable.Routes);

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

        }

Questo è tutto ciò che devi fare sul lato server. Sul lato client, cioè dal browser web, dovresti assicurarti di aggiungere l'intestazione di override come mostrato nello snippet di codice di seguito.

$ .ajax ({

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

  tipo: "POST",

  dati: JSON.stringify (authorData),

  intestazioni: {

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

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

})

Come puoi vedere nel frammento di codice precedente, tutto ciò che devi fare è specificare il metodo HTTP che vuoi invocare nell'intestazione della richiesta - X-HTTP-Method-Override : DELETEoppure X-HTTP-Method-Override : PUT- e quindi effettuare una chiamata POST alla tua risorsa.