HTTP Message Handlers in WEB API

Server-Side HTTP Message Handlers in WEB API

In this article, I am going to discuss the Server-Side HTTP Message Handlers in WEB API with some real-time examples. First, let us understand what is an HTTP Message handler, An HTTP Message Handler in Web API is a class that receives an HTTP request and returns an HTTP response. The Message Handler is derived from the abstract HttpMessageHandler class.

To handle the HTTP Request and to generate the HTTP Response in WeB API, a series of message handlers are chained together. The first handler in the chain receives the HTTP request. Do some processing, and gives the request to the next handler. At some point, the response is generated and goes back up in the chain. This pattern is called a delegating handler. The following diagram shows this process.

Server-Side HTTP Message Handlers in WEB API

Types of HTTP Message Handlers in Web API:

In ASP.NET Web API Framework, there are two types of message handlers are available. They are as follows

  1. The Server Side HTTP Message Handlers
  2. Client Side HTTP Message Handlers

In this article, I am going to discuss the Server-Side HTTP Message Handlers in Web API Framework with some real-time examples. In the next article, I will discuss the Client-Side HTTP Message Handlers in Web API.

Server-Side HTTP Message Handlers in Web API

On the server side, The Web API Framework uses some built-in message handlers which are as follows:

  1. HttpServer: This built-in message handler gets the request from the host.
  2. HttpRoutingDispatcher: This message handler dispatches the request based on the route.
  3. HttpControllerDispatcher: This message handler sends the request to an ASP.NET Web API controller.

You can also create your own custom handlers and then add to the Web API pipeline. The Message handlers are good for cross-cutting concerns (such as authentication and authorization) that operate at the level of HTTP messages rather than controller actions. For example, a custom message handler might do the following things

  1. Read or modify the HTTP Request headers.
  2. Add a response header to the HTTP response.
  3. Validate the requests before they reach the controller (i.e. Authentication and Authorization).

The following diagram shows two custom handlers (Message Handler1 and Message Handler2) inserted into the Web API pipeline:

Server-Side HTTP Message Handlers in WEB API

The above diagram shows message handlers on the Server Side.

Creating Custom Server-Side HTTP Message Handlers in Web API

As we already discussed along with the built-in Server-side Message Handlers, you can also create your own Server-Side HTTP Message Handlers. So let’s discuss how to create the Custom Server-Side HTTP Message handlers in ASP.NET Web API.

To create a custom Server-Side HTTP Message Handler in ASP.NET Web API, you need to create a class which must be derived from the System.Net.Http.DelegatingHandler. That custom class then should override the SendAsync method. SendAsync method has the following signature:

Server-Side Message Handlers in WEB API

The SendAsync method takes an HttpRequestMessage as input and asynchronously returns an HttpResponseMessage. A typical implementation does the following:

  1. Process the request message.
  2. Call the base.SendAsync method to send the request to the inner handler.
  3. The inner handler returns a response message. (This step is asynchronous.)
  4. Process the response message and returns the response to the caller.
A sample code is shown below.
using System.Diagnostics;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;

namespace MessageHandler.Models
{
    public class MessageHandler1 : DelegatingHandler
    {
        protected async override Task<HttpResponseMessage> SendAsync(
            HttpRequestMessage request, CancellationToken cancellationToken)
        {
            Debug.WriteLine("Process request");
            // Call the inner handler.
            var response = await base.SendAsync(request, cancellationToken);
            Debug.WriteLine("Process response");
            return response;
        }
    }
}

Note: The call to the base.SendAsync is asynchronous. If the handler does any work after this call, use the await keyword, as shown in the above example.

A delegating handler can also skip the inner handler and directly create the response. Let’s look at the below example which exactly does the same thing.

using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;

namespace MessageHandler.Models
{
    public class MessageHandler2 : DelegatingHandler
    {
        protected override Task<HttpResponseMessage> SendAsync(
            HttpRequestMessage request, CancellationToken cancellationToken)
        {
            // Create the response.
            var response = new HttpResponseMessage(HttpStatusCode.OK)
            {
                Content = new StringContent("Hello!")
            };

            // Note: TaskCompletionSource creates a task that does not contain a delegate.
            var tsc = new TaskCompletionSource<HttpResponseMessage>();
            tsc.SetResult(response);   
            return tsc.Task;
        }
    }
}

When a delegate handler creates the response without calling the base.SendAsync method, then the request skips the rest of the pipeline. This can be useful for a handler that validates the request creating an error response. We will discuss this with a complete example in our upcoming article.

Adding Custom HTTP Message Handlers to the Pipeline

To add the Custom HTTP Message Handlers on the server side, you need to add the Custom Http Message Handlers to the HttpConfiguration.MessageHandlers collection inside Register method of the WebApiConfig class as shown in the below image:

Server-Side HTTP Message Handlers in WEB API

The Message Handlers are going to call in the same order as they appear in the MessageHandlers collection. The reason is they are nested and the response message travels in the other direction. That is, the last handler is the first one to get the response message.

Notice that you don’t need to set the inner handlers. That is the job of the Web API framework which will automatically connect the inner message handlers.

Now let’s look at some of the examples of custom message handlers.

Example: X-HTTP-Method-Override

The X-HTTP-Method-Override is a non-standard HTTP header. It is basically designed for clients who 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 type. For example:

X-HTTP-Method-Override: PUT

So to support this, we need to create a custom message handler that adds support for X-HTTP-Method-Override:

using System;
using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;

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

        protected override Task<HttpResponseMessage> 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);
        }
    }
}

Explanation of the above code:

In the above 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, then it validates the request header value and then modifies the request method. Finally, the handler calls the 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.

Example: Adding a Custom Response Header

Let’s see an example of a message handler that adds a custom header to every response message:

using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;

namespace MessageHandler.Models
{
    public class CustomHeaderHandler : DelegatingHandler
    {
        async protected override Task<HttpResponseMessage> 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;
        }
    }
}

In the above example, the handler first calls the base.SendAsync method to pass the request to the inner message handler. The inner handler returns a response message, but it does so asynchronously by using the Task<T> object. The response message is not available until base.SendAsync completes asynchronously.

Example: Checking for an API Key

Some web services require the clients to include an API key in their request. The following example shows how a message handler can check the requests for a valid API key:

using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;

namespace MessageHandler.Models
{
    public class ApiKeyHandler : DelegatingHandler
    {
        public string Key { get; set; }

        public ApiKeyHandler(string key)
        {
            this.Key = key;
        }

        protected override Task<HttpResponseMessage> SendAsync(
            HttpRequestMessage request, CancellationToken cancellationToken)
        {
            if (!ValidateKey(request))
            {
                var response = new HttpResponseMessage(HttpStatusCode.Forbidden);
                var tsc = new TaskCompletionSource<HttpResponseMessage>();
                tsc.SetResult(response);
                return tsc.Task;
            }
            return base.SendAsync(request, cancellationToken);
        }

        private bool ValidateKey(HttpRequestMessage message)
        {
            var query = message.RequestUri.ParseQueryString();
            string key = query["key"];
            return (key == Key);
        }
    }
}

The above message handler looks for the API key in the URI query string. (For the above example, we assume that the key is a static string. A real implementation would probably use more complex validation.) If the query string contains the key, the handler passes the request to the inner handler.

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.

NOTE: If the API key applies only to certain controller actions, consider using an action filter instead of a message handler. Action filters run after URI routing is performed.

In the next article, I will discuss how to implement basic authentication using a message handler in ASP.NET Web API.

SUMMARY

In this article, I try to explain Server-Side HTTP Message Handlers in WEB API with real-time examples. I hope this article will help you with your need. I would like to have your feedback. Please post your feedback, question, or comments about this article.

Leave a Reply

Your email address will not be published. Required fields are marked *