Custom Message Handler in Web API




What is Message Handler?

Message Handler is a class that derives from HttpMessageHandler class, receives HTTP request and returns HTTP response.
Message handlers are chain of classes in a pipeline, sitting next to the process of HTTP request and response. The first handler in a pipeline receives an HTTP request, process it and gives the request to the next handler or creates a response that goes back up the chain.

 


Message Handlers can be used on both the server-side and client side. But in this article, we will only consider server-side handlers so as to keep things simple.

Server Side Message Handlers
 
Built-in message handlers in  Web API pipeline:
  • HttpServer: receives the request from host.
  • HttpRoutingDispatcher: channels the request based on route.
  • HttpControllerDispatcher: send the request to the appropriate Controller.
Custom handlers can be added to the pipeline to:
  • Validate requests before they reach the controller
  • Modify request headers
  • Process request message
  • Process response
  • Add response header to responses



Create Custom Message Handler

Create a class that derives from System.Net.Http.DelegatingHandler, then override the SendAsync method like so:


 using System.Net.Http;  
 using System.Threading;  
 using System.Threading.Tasks;  
 namespace MessagehandlerWithWebAPI.Filters  
 {  
   public class RequestFilterHandler:DelegatingHandler  
   {  
     protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)  
     {  
        return base.SendAsync(request, cancellationToken);  
      }  
    }  
  }  

Custom Message handler implementation generally does the following
  1. Receives request message
  2. Process the request message
  3. Send the request to the inner handler by calling base.SendAsync
  4. Receives response message from the inner handler
  5. Process the response
  6. Return the response message to the caller
Custom handler can directly create response by skipping the inner handlers in the pipeline. This can be achieved by creating response without calling base.SendAsync.

Add Custom Handler to the Pipeline

Custom handlers can be added to the pipeline by the following:
  1. Inside the WebApiConfig class
  2. In Global.asax class
Add Handlers in WebApiConfig class like so:


 using MessagehandlerWithWebAPI.Filters;  
 using System.Web.Http;  
 namespace MessagehandlerWithWebAPI  
 {  
   public static class WebApiConfig  
   {  
     public static void Register(HttpConfiguration config)  
     {  
       // Web API configuration and services  
        config.MessageHandlers.Add(new RequestFilterHandler());  
        //config.MessageHandlers.Add(new Handler2());  
        //config.MessageHandlers.Add(new Handler3());  
        // Web API routes  
        config.MapHttpAttributeRoutes();  
        config.Routes.MapHttpRoute(  
          name: "DefaultApi",  
          routeTemplate: "api/{controller}/{id}",  
          defaults: new { id = RouteParameter.Optional }  
        );  
      }  
    }  
  }  

Add custom handlers in Global.asax class like so:


 using MessagehandlerWithWebAPI.Filters;  
 using System.Web.Http;  
 using System.Web.Mvc;  
 using System.Web.Optimization;  
 using System.Web.Routing;  
 namespace MessagehandlerWithWebAPI  
 {  
   public class WebApiApplication : System.Web.HttpApplication  
   {  
      protected void Application_Start()  
      {  
        AreaRegistration.RegisterAllAreas();  
        GlobalConfiguration.Configure(WebApiConfig.Register);  
        GlobalConfiguration.Configuration.MessageHandlers.Add(new RequestFilterHandler());  
        //GlobalConfiguration.Configuration.MessageHandlers.Add(new Handler2());  
        //GlobalConfiguration.Configuration.MessageHandlers.Add(new Handler3());  
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);  
        RouteConfig.RegisterRoutes(RouteTable.Routes);  
        BundleConfig.RegisterBundles(BundleTable.Bundles);  
      }  
    }  
 }  

The handlers are called in sequence they appeared. like so:
RequestFilterHandler  >>  Handler2  >> Handler3 

The response message travels in the other direction, hence the first handler in the pipeline is the last handler to receive  response message. like so:
RequestFilterHandler  <<  Handler2  << Handler3

Sample Project

In the sample project, we will create Web API that returns a list of names, then use custom message handler to validate API key.

Create web API with get method that returns list of names like so:

 using System.Collections.Generic;  
 using System.Web.Http;  
 namespace MessagehandlerWithWebAPI.Controllers  
 {  
   [RoutePrefix("api/v1")]  
   public class NamesController : ApiController  
   {  
     [HttpGet]  
     [Route("names")]  
      public IEnumerable<string> GetNames()  
      {  
        return new List<string>() { "Akin", "Mark","thurbarh"};  
      }  
    }  
  }  

Create a folder called filter, then add new class like so:


 using System.Net.Http;  
 using System.Threading;  
 using System.Threading.Tasks;  
 namespace MessagehandlerWithWebAPI.Filters  
 {  
   public class RequestFilterHandler:DelegatingHandler  
   {  
     protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)  
     {  
        return base.SendAsync(request, cancellationToken);  
      }  
    }  
  }  

Modify the RequestFilterHandler class to validate API key like so:


 using System.Net.Http;  
 using System.Threading;  
 using System.Threading.Tasks;  
 using System.Linq;  
 namespace MessagehandlerWithWebAPI.Filters  
 {  
   public class RequestFilterHandler:DelegatingHandler  
   {  
     protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)  
      {  
        if (!ValidateKey(request))  
        {  
          var res = request.CreateResponse(System.Net.HttpStatusCode.Forbidden,  
            new  
            {  
              error = true,  
              message = "Access Denied, Invalid request",  
            });  
          var tsk = new TaskCompletionSource<HttpResponseMessage>();  
          tsk.SetResult(res);  
          return tsk.Task;  
        }  
        return base.SendAsync(request, cancellationToken);  
      }  
      private bool ValidateKey(HttpRequestMessage request)  
      {  
        if (!request.Headers.Contains("X-AUTH-KEY")) return false;  
        return request.Headers.GetValues("X-AUTH-KEY").FirstOrDefault()=="QHU7V2K0=YWQ";  
      }  
    }  
  }  

Add the custom handler to the pipeline in Global.asax class like so:


 using MessagehandlerWithWebAPI.Filters;  
 using System.Web.Http;  
 using System.Web.Mvc;  
 using System.Web.Routing;  
 namespace MessagehandlerWithWebAPI  
 {  
   public class WebApiApplication : System.Web.HttpApplication  
   {  
     protected void Application_Start()  
      {  
        AreaRegistration.RegisterAllAreas();  
        GlobalConfiguration.Configure(WebApiConfig.Register);  
        GlobalConfiguration.Configuration.MessageHandlers.Add(new RequestFilterHandler());  
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);  
        RouteConfig.RegisterRoutes(RouteTable.Routes);  
      }  
    }  
  }  

Build and run the application, use postman to invoke the GetNames() action.
You should have:


Add the API key to the request header and try again like so:

The source code of the sample project can be downloaded here

I hope the article is helpful, kindly leave comment in the comment section below.

Thank you for your time.

                                                                          X-HTTP-Method-Override For Rest Web API >>>
Custom Message Handler in Web API Custom Message Handler in Web API Reviewed by Akintunde Toba on February 03, 2020 Rating: 5

No comments:

Home Ads

Powered by Blogger.