Posted on 9/19/2020 10:45:53 AM by Admin

Http Message Handler and HttpClient Message Handler

In order to understand Http Message handler , you first need to understand Http Client ,Http Server and Web API. An HTTP "client" is a program (Web browser or any other client) that establishes a connection to a server for the purpose of sending one or more HTTP request messages. An HTTP "server" is a program ( generally a web server like Apache Web Server or Internet Information Services IIS, etc. ) that accepts connections in order to serve HTTP requests by sending HTTP response messages. Thus both Http Client and Http Server are programs which are able to receive and send Http Messages.

Http Client like browsers are designed to construct http messages (http request header and http request body) and send it to the http server like IIS ,similarly the Http Servers are designed to construct http messages (http response header and Http Response body) and send it to Http Client.

Asp.Net web API is a framework that is used to create Http Services , Services means self contained independent functionalities for example Facebook's like service , in order to integrate this functionality into an application ,you do not need any other functionalities of Facebook , means is completely independent self working functionality , when any such service utilizes the features of Http like http verbs, content negotiation, Authentication etc and can be consumed over http with a unique URL as if it is sending a unique resource from the web then we call it a Rest or pure Http Service. For example http://fb.com/Likes/count?postUrl=myurl, may give you the count of all likes on a specific Post , similarly http://fb.com/Likes/friends?postUrl=myurl , may return you list of friends who liked your post. So at the end of the day such services return some resources from a unique address on the web to the client.

Now wait and think , it is great that we can create http services with web API but the Client (Browser etc) cannot send Http request directly to the web API Controller, Only the Http Server like IIS has that ability to catch Http Messages that is sent by the client but somehow Http Messages should reach to the web API , this is where we need Http Message handler.

Similarly , it is Okay that we have Http Clients like browser and standalone http Client like Fiddler and Postman etc but wouldn't it be great if somehow we could send http request from our own application like windows form or MVC controller to Http server and could get response back from the Server. Then again, this is the place where we need Http Message handler.

In short web API uses some inbuilt http Message handler to receive http request from Http server(IIS) and Send response back to them, we call it Server side Http Message Handler. On the other hand if we want to send Http requests to Http server from an application or want to receive Http messages from an Http server directly to our application then we use HttpClient ( a base class for sending HTTP requests and receiving HTTP responses from a resource identified by a URI) , which uses some inbuilt Http Message Handler to send or receive Http messages from Http Server.

Now I don't think there is any need to define Http Message Handler , yet I know your soul won't be satisfied until it gets a proper definition, so here it is :
A message handler is a class that receives an HTTP request and returns an HTTP response. Message handlers derive from the abstract HttpMessageHandler class.

Typically, a series of message handlers are chained together. The first handler receives an HTTP request, does some processing, and gives the request to the next handler. At some point, the response is created and goes back up the chain. This pattern is called a delegating handler.

Http Message Handler is used on both sides, On the client side, the HttpClient class uses a message handler to process requests. The default handler is HttpClientHandler, which sends the request over the network and gets the response from the server.

On the server side, the Web API pipeline uses some built-in message handlers:
    • HttpServer gets the request from the host.
    • HttpRoutingDispatcher dispatches the request based on the route.
    • HttpControllerDispatcher sends the request to a Web API controller.

We can insert custom message handlers into the client pipeline as well as into the web API pipeline.

How to create a custom Message Handler

To write a custom message handler,create a class and inherit it from System.Net.Http.DelegatingHandler and override the SendAsync method. Here is the method signature:


Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken); 



The method takes an HttpRequestMessage as input and asynchronously returns an HttpResponseMessage. A typical implementation does the following:
    • Process the request message.
    • Call base.SendAsync to send the request to the next handler(inner handler).
    • The inner handler returns a response message. (This step is asynchronous.)
    • Process the response and return it to the caller.

Adding Custom Message Handlers to the HttpClient Pipeline

To add custom handlers to HttpClient, use the HttpClientFactory.Create method:


    HttpClient client = HttpClientFactory.Create(new Handler1(), new Handler2(), new Handler3());

Message handlers are called in the order that you pass them into the Create method. Because handlers are nested, the response message travels in the other direction. That is, the last handler is the first to get the response message.

Adding Custom Message Handlers to the web API Pipeline

To add a message handler on the server side, add the handler to the HttpConfiguration.MessageHandlers collection. you can do this inside the WebApiConfig class:


   public static class WebApiConfig
   {
    public static void Register(HttpConfiguration config)
    {
        config.MessageHandlers.Add(new MessageHandler1());
        config.MessageHandlers.Add(new MessageHandler2());

        // Other code not shown...
    }
   }

Message handlers are called in the same order that they appear in MessageHandlers collection.

Message Handlers
Message Handlers

Now it's time to do some practical demonstration. Let's start with the Client Side.

Step 1.Create a service using Asp.Net Web API , we will call it from another application let's say winform application using HttpClient.


   public class EmployeeController : ApiController
    {
        public HttpResponseMessage Get()
        {
            try
            {
                var emps = LoadEmpData();
                if (emps != null)
                {
                    return Request.CreateResponse(HttpStatusCode.OK,emps);
                }
                return Request.CreateErrorResponse(HttpStatusCode.NoContent,"No Employees found")
            }
            catch(Exception ex)
            {
               return Request.CreateErrorResponse(HttpStatusCode.InternalServerError,ex.Message);
            }
        }

        public List LoadEmpData()
        {
            List Employees = new List(){
                    new Employee(){Name="ramesh",Age=20},
                    new Employee(){Name="Rihana",Age=21},
                    new Employee(){Name="Michael",Age=34}

                };
            return Employees;
        }
    }
    namespace WebAPITest.Models
    {
    public class Employee
    {
        public string Name { get; set; }
        public int Age { get; set; }
    }
    }

Step 2.Create a windows Form Application with a DataGridView and a Button control and In the code behind of Button_Click event write below code.

Winform Client
Winform Client APP

   namespace Client
    {
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private async void button1_Click(object sender, EventArgs e)
        {
            HttpClient _Client = new HttpClient();
            _Client.BaseAddress = new Uri("http://localhost:58572/");
            _Client.DefaultRequestHeaders.Accept.Clear();
            _Client.DefaultRequestHeaders.Accept.Add(
              new MediaTypeWithQualityHeaderValue("application/json"));

            HttpResponseMessage response = await _Client.GetAsync("api/Employee");
          
            if (response.IsSuccessStatusCode)
            {
               var res=  response.Content.ReadAsAsync>().Result.ToList();
                dataGridView1.DataSource = res;
               
            }

        }
    }
    public class Employee
    {
        public string Name { get; set; }
        public int Age { get; set; }
    }
   }

Step 3.Run both the application , and when you click call API button , you will get the below result.

Winform Client result
Winform Client APP with Data from API

This is how we use HttpClient to call web API from other applications. Now let's create a custom message handler and add it to the HttpClient pipeline.

Custom Message Handlers into HttpClient pipeline

The biggest question is, why to create a Message handler on the Client Pipeline ? and which are the real world scenarios where built-in HttpClienthandler is inefficient and we need some additional logic to add to the Client Pipeline.

Some of the scenarios are as follow:
    • Logging
    • Retrying failed requests
    • Unit Testing

Let's create Custom Message Handler for some of these.

Logging:

Logging sent requests and received responses can help diagnose issues. This can easily be done with a custom delegating handler.
Step 1.Create a folder in your windows form project and name it as Handlers.
Step 2.Add a class file inside the folder and Name it as LoggingHandler.
Step 3.Inherit the class from DeligatingHandler and override the SendAsync() method like below.


  namespace Client.Handlers
   {
    public class LoggingHandler : DelegatingHandler
    {
      protected override async Task SendAsync(HttpRequestMessage request, CancellationToken 
      cancellationToken)
        {
            Console.WriteLine("Request:");
            Console.WriteLine(request.ToString());
            if (request.Content != null)
            {
                Console.WriteLine(await request.Content.ReadAsStringAsync());
            }
            Console.WriteLine();

            HttpResponseMessage response = await base.SendAsync(request, cancellationToken);

            Console.WriteLine("Response:");
            Console.WriteLine(response.ToString());
            if (response.Content != null)
            {
                Console.WriteLine(await response.Content.ReadAsStringAsync());
            }
            Console.WriteLine();

            return response;
        }
    }
   }

Step 4.Run your web API project first and then run the windows app, and click on Call API button. You will get the result as expected , meaning your dataGridView will be filled with the data coming from the server but at the same time in the output console you will get the below result.

Output console window
Request and Response log in Output console

Retrying failed requests

Another interesting use case for HTTP message handlers is to automatically retry failed requests. For instance, the server you’re talking to might be temporarily unavailable (503), or it could be throttling your requests (429), or maybe you lost Internet access. Handling the retry for these cases at the application level is a pain, because it can happen virtually in any part of your code. Having this logic at the lowest possible level and implemented in a way that is completely transparent to the callers can make things much easier.

We can write our own logic to retry request based on different types of error response, but I am going to use Polly. Polly is a .NET resilience and transient-fault-handling library that allows developers to express policies such as Retry, Circuit Breaker, Timeout, Bulkhead Isolation, and Fallback in a fluent and thread-safe manner. Polly targets .NET 4.0, .NET 4.5 and .NET Standard 1.1.

Step 1.Add a class file inside the folder Handlers and Name it as HttpRetryHandler.
Step 3.Inherit the class from DeligatingHandler and override the SendAsync() method like below.


  namespace Client.Handlers
  {
   public class HttpRetryHandler : DelegatingHandler
    {
       protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
       {
           return Policy
            .HandleResult(message => !message.IsSuccessStatusCode)
        .WaitAndRetryAsync(3, i => TimeSpan.FromSeconds(2), (result, timeSpan, retryCount, context) =>
        {
            Debug.Write("Request failed with"+result.Result.StatusCode+ "Waiting"+timeSpan+"before next retry. Retry attempt"+retryCount);
        })
            .ExecuteAsync(() => base.SendAsync(request, cancellationToken));
           
       }
     }
    }

Step 3. To test whether our Retry Handler is working or not , let's create another handler which will add a custom header to the request on each retry then based on the appropriate custom header value web API will send the response.
  • Add a class file inside the folder Handlers and Name it as CustomDelegatingHandler.
  • Inherit the class from DeligatingHandler and override the SendAsync() method like below.

   namespace Client.Handlers
   {
    public class CustomDelegatingHandler : DelegatingHandler
    {
        private int _count = 0;

        protected override Task SendAsync(HttpRequestMessage request,
            CancellationToken cancellationToken)
        {
            if (_count == 0)
            {
                _count++;
                request.Headers.Add("cust", "first");
                return base.SendAsync(request, cancellationToken);
            }
            if(_count==1){
                _count++;
                request.Headers.Clear();
                request.Headers.Add("cust", "second");
                return base.SendAsync(request, cancellationToken);
                            }
            request.Headers.Clear();
            request.Headers.Add("cust", "third");
            return base.SendAsync(request, cancellationToken);
        }
     }
   }

Step 4.Open EmployeeService (web api project) and modify the Get() method like below.

   public HttpResponseMessage Get()
        {
            try
            {
                string HeaderValue = "1";
                if (Request.Headers.Contains("cust"))
                {
                    HeaderValue = Request.Headers.GetValues("cust").FirstOrDefault();
                }
                if (HeaderValue == "third")
                {
                    var emps = LoadEmpData();
                    if (emps != null)
                    {
                        return Request.CreateResponse(HttpStatusCode.OK, emps);
                    }

                    return Request.CreateErrorResponse(HttpStatusCode.NoContent, "No Employees found");
                }

                return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, "error");
            }
            catch(Exception ex)
            {
               return Request.CreateErrorResponse(HttpStatusCode.InternalServerError,ex.Message);
            }
        }

Step 5.Open your windows App (Client APP) and Add these two handlers to the HttpClient pipeline. Now , your windows form1.cs should look like below.


   namespace Client
   {
    public partial class Form1 : Form
    {
        private static readonly HttpClient _Client;
        public Form1()
        {
           
            InitializeComponent();
        }
   
        private async void button1_Click(object sender, EventArgs e)
        {
             _Client = HttpClientFactory.Create(new HttpRetryHandler(),new     CustomDelegatingHandler(),new LoggingHandler());
            _Client.BaseAddress = new Uri("http://localhost:58572/");
            _Client.DefaultRequestHeaders.Accept.Clear();
            _Client.DefaultRequestHeaders.Accept.Add(
              new MediaTypeWithQualityHeaderValue("application/json"));

            HttpResponseMessage response = await _Client.GetAsync("api/Employee");
          
            if (response.IsSuccessStatusCode)
            {
                var res = response.Content.ReadAsAsync>().Result.ToList();
                dataGridView1.DataSource = res;
              
            }

        }
    }
    public class Employee
    {
        public string Name { get; set; }
        public int Age { get; set; }
    }
  }

At this moment run your API and windows application and click the Call API button of windows form application , you will get the similar result , your DataGridView will be filled with Employee's Data but in the output pane of visual studio you will get below results.

Output console window Handlers
Request and Response log in Output console (Retry Handler result)

As you can see in the figure above , the request has been send three times in the interval of 2 seconds, in the third attempt the web API is sending 200 OK status code with employee's data.

Unit testing

Sometimes ,you don’t want a class which is using HttpClient to actually send requests to the real server, you just want to ensure that the requests it sends are correct, and that it reacts correctly to specific responses. An easy solution to this problem is to create a “stub” handler, and inject it into your class to use instead of HttpClientHandler. It is the HttpClientHandler message handler in the HttpClient pipeline which actually sends the request to the Network, we can replace this default handler with our StubHandler, actually we won't replace the default HttpClientHandler will just pass the stubHandler as the last message handler in the HttpClient pipeline and will not use the base.sendAsync() , so the default handler will be disconnected and the StubHandler will be the last in the pipeline which will send the actual response without sending the request to the web API in our case.
Step 1.Add a class file inside the folder Handlers and Name it as HttpRetryHandler.
Step 3.Inherit the class from DeligatingHandler and override the SendAsync() method like below.


   public class StubDelegatingHandler : DelegatingHandler
    {
        private int _count = 0;

        protected override Task SendAsync(HttpRequestMessage request,
            CancellationToken cancellationToken)
        {
            if (_count == 0)
            {
                _count++;
               return Task.FromResult(new HttpResponseMessage(HttpStatusCode.InternalServerError));
            }
           
            var response = new HttpResponseMessage(HttpStatusCode.OK);
            return Task.FromResult(response);
        }
    }


Step 3. Add this handler into the HttpClient pipeline in the windows form1.cs like below.


    private async void button1_Click(object sender, EventArgs e)
        {
            HttpClient _Client = HttpClientFactory.Create(new HttpRetryHandler(), new LoggingHandler(), new StubDelegatingHandler());
            _Client.BaseAddress = new Uri("http://localhost:58572/");
            _Client.DefaultRequestHeaders.Accept.Clear();
            _Client.DefaultRequestHeaders.Accept.Add(
              new MediaTypeWithQualityHeaderValue("application/json"));

            HttpResponseMessage response = await _Client.GetAsync("api/Employee");
          
            if (response.IsSuccessStatusCode)
            {
                var res = response.Content.ReadAsAsync>().Result.ToList();
                dataGridView1.DataSource = res;
               
               
            }

        }

At this moment run the application and click Call API button and check the output pane of visual studio you will get below results.

response from stub handler
response from stub handler

As you can see from the figure the request are being send three times due to retry handler but the response is coming from stub handler and the request is not reaching to the Web API , what we actually wanted.

Some key points to remember when using HttpClient in your application.

1. HttpClient is intended to be instantiated once and re-used throughout the life of an application. Instantiating an HttpClient class for every request will exhaust the number of sockets available under heavy loads. This will result in SocketException errors. Below is an example using HttpClient correctly.


    // for mvc application
   public class HomeController :Controller
   {
    private static readonly HttpClient HttpClient;

    static HomeController()
    {
        HttpClient = new HttpClient();
    }
   }
   // for webform/ windows form
   //Create a singleton class that exports a single HttpClient that every object uses. HttpClient is thread //safe as long as you use SendAsync 
    in all your calls (i.e. don't modify any Default... headers)

2. The DefaultRequestHeaders in the HttpClient class, sets headers to be sent with each request using that client object, hence the name Default Request Headers. For example sometimes we need to define and pass custom headers with the request , for example a Service may ask you to include a custom header for versioning purpose. Read this article to know what do I actually mean. Similarly sometimes we need to pass the Authorization Header that contains Http Scheme type and credentials or Token value to access a specific end point. This can easily be achieved like below.


     using (var client = new HttpClient()) {
    client.BaseAddress = new Uri("https://api.sharpencode.com/");
    client.DefaultRequestHeaders.Accept.Clear();
    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "xxxxxxxxxxxxxxxxxxxx");
    client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
     client.DefaultRequestHeaders.Add("X-Version","1");

    var  response = client.PostAsJsonAsync("rest/message", myObject).Result;
     }

But there is a problem with this approach , DefaultRequestHeaders is a property of the HttpClient object; if multiple messages are sent through a given HttpClient, all such messages will all have the same DefaultRequestHeaders. if you need to change or add headers use Headers property of the HttpRequestMessage class. You can add custom headers there, which will be sent with that HTTP request only.


    var  client = new HttpClient();
    var  httpRequestMessage = new HttpRequestMessage
        {
            Method = HttpMethod.Post,
            RequestUri = new Uri("https://api.sharpencode.com/rest/message"),
            Headers = { 
                { HttpRequestHeader.Authorization.ToString(), "Bearer xxxxxxxxxxxxxxxxxxxx" },
                { HttpRequestHeader.Accept.ToString(), "application/json" },
                { "X-Version", "1" }
            },
            Content = new StringContent(JsonConvert.SerializeObject(svm))
        };

    var  response = client.SendAsync(httpRequestMessage).Result;

We discussed the Role of custom Http Message handler in the HttpClient pipeline, now let's discuss what are the scenarios where we can create custom Http message handler in the server side that is in web API pipeline.

Custom Message Handlers into the web API pipeline

we can create and add custom message handler to the web API pipeline for several reasons , some of them are as follows.
  • To add a custom header to every response message.
  • To Check for an API Key in the request.
  • To add support for X-HTTP-Method-Override.

We will use the same Employee Service web API, that we have created few minutes back , And will try to add different custom message Handlers into the pipeline one by one. Remove all the unnecessary code from the Employee Controller, now your Controller should look like below.


  namespace WebAPITest.Controllers
   {
    public class EmployeeController : ApiController
    {
        public HttpResponseMessage Get()
        {
            try
            {
              
                    var emps = LoadEmpData();
                    if (emps != null)
                    {
                        return Request.CreateResponse(HttpStatusCode.OK, emps);
                    }

                    return Request.CreateErrorResponse(HttpStatusCode.NoContent, "No Employees found");
             
            }
            catch(Exception ex)
            {
               return Request.CreateErrorResponse(HttpStatusCode.InternalServerError,ex.Message);
            }
        }

        public List LoadEmpData()
        {
            List Employees = new List(){
                    new Employee(){Name="ramesh",Age=20},
                    new Employee(){Name="Rihana",Age=21},
                    new Employee(){Name="Michael",Age=34}

                };
            return Employees;
        }
    }
  }

Adding a Custom Response Header

We have already learnt how to create a custom Message handler , we just need to inherit the class from DelegatingHandler and override the ,b>SendAsync() method.
Step 1.Create a folder and Name it Handlers into the Web API project.
Step 2.Add a Class file into the Handlers folder and Name it as ResponseHeaderMessageHandler.
Step 3.Inherit the class from Delegating handler and override the SendAsync() method like below.


  namespace WebAPITest.Handlers
   {
    public class ResponseHeaderMessageHandler:DelegatingHandler
    {
       async protected override System.Threading.Tasks.Task SendAsync(HttpRequestMessage request, 
    CancellationToken cancellationToken)
        {
               HttpResponseMessage response = await base.SendAsync(request, cancellationToken);
                response.Headers.Add("X-Custom-Header", "This is my custom header.");
              return response;
        }
    }
  }

First, the handler calls base.SendAsync to pass the request to the inner message handler. The inner handler returns a response message, but it does so asynchronously using a Task object. The response message is not available until base.SendAsync completes asynchronously.

Step 4. Add the message handler into the web API pipeline. I have already discussed ,how to add a message handler into the web API pipeline in the beginning of the article.
  • Go to App_Start folder and open webApiConfig.cs class and add one line of code in the Register() method like below.


    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            // Web API configuration and services

            // Web API routes
            config.MapHttpAttributeRoutes();

            //Add Message Handlers
            config.MessageHandlers.Add(new ResponseHeaderMessageHandler());


            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
        }
    }

Step 5.Run the web API and send a get request from windows Client Application using HttpClient (with LoggerHandler added into the HttpClientPipeline) that we had created earlier or use any standalone Http Client like fiddler. I am using fiddler to check the response headers.

Response Header
Custom Response Header

Checking for an API Key

Some web services require clients to include an API key in their request. We can create a Message handler to check for a valid API key in the request.
step 1.Add a new class file into the Handlers folder and name it as APIKeyHandler.
step 2.Inherit the class from DelegatingHandler and override the SendAsync() method like below.


   namespace WebAPITest.Handlers
   {
    public class APIKeyHandler : DelegatingHandler
    {
        //set a default API key 
        private const string yourApiKey = "X-some-key";

        protected override async Task SendAsync(HttpRequestMessage request, CancellationToken 
      cancellationToken)
        {
            bool isValidAPIKey = false;
            IEnumerable lsHeaders;
            //Validate that the api key exists

            var checkApiKeyExists = request.Headers.TryGetValues("API_KEY", out lsHeaders);

            if (checkApiKeyExists)
            {
                if (lsHeaders.FirstOrDefault().Equals(yourApiKey))
                {
                    isValidAPIKey = true;
                }
            }

            //If the key is not valid, return an http status code.
            if (!isValidAPIKey)
                return request.CreateResponse(HttpStatusCode.Forbidden, "Bad API Key");

            //Allow the request to process further down the pipeline
            var response = await base.SendAsync(request, cancellationToken);

            //Return the response back up the chain
            return response;
        }
     }
   }

  • This handler looks for an API key (API_KEY) in the header of every HTTP request, and passes the request to the controller only if a valid API key is present in the request header. (For this example, we assume that the key is a static string. A real implementation would probably use more complex validation.)
  • If the request does not have a valid key, the handler creates a response message with status 403, Forbidden. In this case, the handler does not call base.SendAsync, so the inner handler never receives the request, nor does the controller. Therefore, the controller can assume that all incoming requests have a valid API key.

Step 3.Add the message handler into the web API pipeline.


   public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            // Web API configuration and services

            // Web API routes
            config.MapHttpAttributeRoutes();

            //Add Message Handlers
            config.MessageHandlers.Add(new ResponseHeaderMessageHandler());
            config.MessageHandlers.Add(new APIKeyHandler());


            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
        }
    }

Step 4.First time ,Issue a get request without passing any API_Key and check the response.

Response without API key
Response without API key
Response header without API key
Response header without API key

As you can see, in the response body we are getting Bad API Key, and in the response header we are getting 403 forbidden status code, so clearly the request has not reached to the web API Controller.

Step 5.Issue the get request with a valid API key and check the response header and response body.

Request with API key
Request with API key
Response  with API key
Response when API key is used
Response header when API key
Response header when API key is sent

As we can see, when a valid API key has been issued , we get the Employees data in the response body and 200 ok status code in the response header.

X-HTTP-Method-Override

There might be some customers/Clients who are against the idea of using GET, POST, PUT, and DELETE, and only use GET and POST.

Sometimes this is because of a browser or client limitation, sometimes it's a really tense corporate firewall. what they use is, X-HTTP-Method-Override which is a non-standard HTTP header. It is designed for clients that cannot send certain HTTP request types, such as PUT or DELETE. Instead, the client sends a POST request and sets the X-HTTP-Method-Override header to the desired method. For example:


     X-HTTP-Method-Override: PUT

To the server such request says "No, seriously, I know I got here via a POST, but use this one (Put) instead."

But the web API know nothing about X-Http-Method-Override, we have to tell the web API about this. we can add support X-HTTP-Method-Override by creating a simple message handler and adding it to the web API pipeline.
Step 1.Add a new class file into the Handlers folder and name it as MethodOverrideHandler.
Step 2.Inherit the class from DelegatingHandler and override the SendAsync() method like below.


    public class MethodOverrideHandler : DelegatingHandler      
    {
    readonly string[] _methods = { "DELETE", "HEAD", "PUT" };
    const string _header = "X-HTTP-Method-Override";

    protected override Task SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken)
    {
        // Check for HTTP POST with the X-HTTP-Method-Override header.
        if (request.Method == HttpMethod.Post && request.Headers.Contains(_header))
        {
            // Check if the header value is in our methods list.
            var method = request.Headers.GetValues(_header).FirstOrDefault();
            if (_methods.Contains(method, StringComparer.InvariantCultureIgnoreCase))
            {
                // Change the request method.
                request.Method = new HttpMethod(method);
            }
        }
        return base.SendAsync(request, cancellationToken);
     }
   }

In the SendAsync method, the handler checks whether the request message is a POST request, and whether it contains the X-HTTP-Method-Override header. If so, it validates the header value, and then modifies the request method. Finally, the handler calls base.SendAsync to pass the message to the next handler.

When the request reaches the HttpControllerDispatcher class, HttpControllerDispatcher will route the request based on the updated request method.

Message handlers in client side
HttpClient Message Handlers
Server side message handlers
Message handlers in web API