Take advantage of message handlers to execute cross cutting concerns earlier in the Web API life cycle Message handlers in Web API provide you the opportunity to process, edit, or decline an incoming request before it reaches the HttpControllerDispatcher. Message handlers are executed much earlier in the request processing pipeline, hence they are a great place to implement cross cutting concerns in Web API. Implementing a custom message handler All message handlers derive from the class HttpMessageHandler. To build your own message handler, you should extend the DelegatingHandler class. Note that the DelegatingHandler class in turn derives from the HttpMessageHandler class. Consider the following Web API controller. public class DefaultController : ApiController { public HttpResponseMessage Get() { return Request.CreateResponse(HttpStatusCode.OK, "Inside the Default Web API Controller..."); } } To create a message handler, you need to extend the DelegatingHandler class and override the SendAsync method. public class IDGHandler : DelegatingHandler { protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { return base.SendAsync(request, cancellationToken); } } The Web API request processing pipeline includes a few built-in message handlers. These include the following: HttpServer — this is used to retrieve the request from the host HttpRoutingDispatcher — this is used to dispatch the request based on the route configured HttpControllerDispatcher — this is used to send the request to the respective controller You can add message handlers to the pipeline to perform one or more of the following operations. Perform authentication and authorization Logging the incoming requests and the outgoing responses Add response headers to the response objects Read or modify the request headers The following code snippet shows how you can implement a simple message handler in Web API. public class IDGHandler : DelegatingHandler { protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { var response = new HttpResponseMessage(HttpStatusCode.OK) { Content = new StringContent("Inside the IDG message handler...") }; var task = new TaskCompletionSource<HttpResponseMessage>(); task.SetResult(response); return await task.Task; } } The IDG message handler doesn’t process the request message — it creates response message and then returns it. You can also call the base version of the SendAsync method if you wouldn’t like to do anything with the incoming request as shown in the code listing below. public class IDGHandler : DelegatingHandler { protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { return await base.SendAsync(request, cancellationToken); } } You can also write code to log the Http requests and the responses that go out in the SendAsync method. To execute the Web API you can use a test method like the one given below. [TestMethod] public void WebAPIControllerTest() { HttpClient client = new HttpClient(); var result = client.GetAsync(new Uri("http://localhost/IDG/api/default/")).Result; string responseMessage = result.Content.ReadAsStringAsync().Result; Assert.IsTrue(result.IsSuccessStatusCode); } When you execute the test method, the message “Inside the Default Web API Controller…” is returned as a response message and the test passes. Oh! We did create a message handler, but we are yet to register it to the message handling pipeline. You would now need to let the Web API infrastructure know where your custom handler exists. To do this, you should register your custom handler in the pipeline. You can register the IDG custom message handler we just created in the Register method of the WebApiConfig class as shown below. public static void Register(HttpConfiguration config) { GlobalConfiguration.Configuration.MessageHandlers.Add(new IDGHandler()); } When you execute the test method again, the text message “Inside the logging message handler…” is returned as a response message and the test passes. Note that you can also register multiple message handlers to the message handling pipeline as shown in the code snippet below. public static void Register(HttpConfiguration config) { GlobalConfiguration.Configuration.MessageHandlers.Add(new MessageHandlerA()); GlobalConfiguration.Configuration.MessageHandlers.Add(new MessageHandlerB()); GlobalConfiguration.Configuration.MessageHandlers.Add(new MessageHandlerC()); } The message handlers would be executed in the order in which they have been added to the pipeline and the response would be returned in the reverse order. In other words, at the time of the incoming request, the message handlers are executed in the order in which they are registered. During the outgoing response, the process is just reversed. So, the message handlers are executed in the reverse order of their registration to the pipeline. You can also implement a message handler that inspects the incoming request and checks if the request contains a valid api key. If the api key is not present or is not valid, it returns an appropriate error message. The following code listing shows how you can do this — I’m leaving it to you to write the code to validate the api key anyway. protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { string key = HttpUtility.ParseQueryString(request.RequestUri.Query).Get("key"); string errorMessage = "You need to specify the api key to access the Web API."; try { if (!string.IsNullOrWhiteSpace(key)) { return base.SendAsync(request, cancellationToken); } else { HttpResponseMessage response = request.CreateErrorResponse(HttpStatusCode.Forbidden, errorMessage); throw new HttpResponseException(response); } } catch { HttpResponseMessage response = request.CreateErrorResponse(HttpStatusCode.InternalServerError, "An unexpected error occured..."); throw new HttpResponseException(response); } } Related content feature What is Rust? Safe, fast, and easy software development Unlike most programming languages, Rust doesn't make you choose between speed, safety, and ease of use. Find out how Rust delivers better code with fewer compromises, and a few downsides to consider before learning Rust. By Serdar Yegulalp Nov 20, 2024 11 mins Rust Programming Languages Software Development how-to Kotlin for Java developers: Classes and coroutines Kotlin was designed to bring more flexibility and flow to programming in the JVM. Here's an in-depth look at how Kotlin makes working with classes and objects easier and introduces coroutines to modernize concurrency. By Matthew Tyson Nov 20, 2024 9 mins Java Kotlin Programming Languages analysis Azure AI Foundry tools for changes in AI applications Microsoft’s launch of Azure AI Foundry at Ignite 2024 signals a welcome shift from chatbots to agents and to using AI for business process automation. By Simon Bisson Nov 20, 2024 7 mins Microsoft Azure Generative AI Development Tools news Microsoft unveils imaging APIs for Windows Copilot Runtime Generative AI-backed APIs will allow developers to build image super resolution, image segmentation, object erase, and OCR capabilities into Windows applications. By Paul Krill Nov 19, 2024 2 mins Generative AI APIs Development Libraries and Frameworks Resources Videos