How to use correlation IDs in ASP.Net Web API

When working with microservices that communicate over the HTTP protocol, you will want to use correlation IDs to track individual requests. Because requests might flow through many services that are spread across multiple systems, tracking them with correlation IDs will be your only hope of detecting and diagnosing errors that might creep into the middleware systems. This article discusses what correlation IDs are, why they are useful, and how they can be used in ASP.Net Web API.

What are correlation IDs?

Let’s assume you have implemented a microservices architecture. In an application comprised of microservices, different aspects of incoming requests will be handled by different microservices, all working asynchronously on their specific tasks and ultimately coming together to generate the response. Now, if something goes wrong, how would you determine by looking at the logs exactly where the request failed? Your logs might contain millions upon millions of log messages. It would be a daunting task to find the relevant log entries among so many messages.

The basic idea is that you may want to track every request. Because the request may be executed by different service components, you need a way to tie all of these service components to the request. Here’s exactly where a correlation ID comes to the rescue. A correlation ID is a unique identifier that provides a way to correlate all of the different micro tasks to the same macro operation. By ensuring that all of the responses contain the same unique identifier, you allow for the tracking and debugging of each request.

Using correlation IDs in Web API

ASP.Net Web API is a lightweight framework for building RESTful services that can run over HTTP. It has been the framework of choice for building RESTful services in ASP.Net for quite some time now. In this example, we will implement a message handler to store a correlation ID in the response header, so that we can send that ID back to the client.

Message handlers are used to process, edit, or even decline an incoming request before it reaches the HttpControllerDispatcher in Web API. Incidentally, HttpControllerDispatcher is a built-in message handler that dispatches the request to the HTTP controller. We can take advantage of our own message handler to add a response header much earlier in the request processing pipeline. Note that you should also include the correlation ID in every log message so that you can track individual HTTP requests.

Create a simple Web API project in Visual Studio and create a class named CorrelationIdHandler that extends the DelegatingHandler class. Our custom message handler will have this basic form:

public class CorrelationIdHandler : DelegatingHandler
{
}

The following code snippet can be used to add a correlation ID to the response header.

response.Headers.Add(CorrelationIdHeaderName, request.GetCorrelationId().ToString());

The GetCorrelationId() extension method first checks to see if the correlation ID is present in the request. If the correlation ID is present, the method retrieves the correlation ID from the request object and adds it to the response header. If the correlation ID is not present, it generates one and adds it to the response header.

Here’s the complete source code of the message handler for your reference:

public class CorrelationIdHandler : DelegatingHandler
{        
private const string key ="X-Correlation-ID";        
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var response = await base.SendAsync(request, cancellationToken);
response.Headers.Add(key, request.GetCorrelationId().ToString());
return response;
}
}

You should add the custom message handler to the MessageHandlers collection of the HttpConfiguration object. Here’s how you can do this in the Register method of the WebApiConfig class.

public static void Register(HttpConfiguration config)
{
// Usual code here
config.MessageHandlers.Add(new CorrelationIdHandler());
}

The following unit test method can be used to retrieve the correlation ID from the HTTP response.

 [TestMethod]
public void CorrelationIdTest()
{
HttpClient client = new HttpClient();
client.BaseAddress = new Uri(“http://localhost:10564/“);
string key ="X-Correlation-ID";
IEnumerable<string> correlationIds = null;
var response = client.GetAsync(“api/values/“).Result;
if (response.Headers.Contains(key))
{
response.Headers.TryGetValues(key, out correlationIds);
}
string correlationId = correlationIds.First();
Assert.IsNotNull(correlationId);
}

The next step is including the correlation ID in the logs. To do this, you should capture the correlation ID from the response header and add it to your log context so that all writes to the log include the correlation ID.

Finally, note that the approach to implementing correlation IDs in ASP.Net MVC Core is a bit different. To accomplish the same as above using ASP.Net MVC Core, you would have to write some middleware, because ASP.Net MVC Core does not have message handlers. I will demonstrate how to do this together with logging in a future article.

Source