Implement your own correlation ID in .Net core in a few simple steps

Share this post

Cover image by Gerd Altmann from Pixabay

The correlation ID is a unique identifier that is added to the incoming request to identify the context, and the request, as it passes through the different components and services. It can either be generated when the request reaches the API or extracted from its headers in case it already has it.

Let’s start by creating a new project, using the the CLI:

dotnet new console -n LearnCorrelationId

First, we need to create a correlation ID provider component that will get or set the correlation Id for the requests. To do this, we need to create the following basic interface that we will implement later on:

public interface ICorrelationIdProvider
    {
        string Get();
        void Set(string correlationId);
    }

Now we can create the correlation ID provider class, which implements the ICorrelationIdProvider interface:

public class CorrelationIdImp: ICorrelationIdProvider {
  private string _correlationId = Guid.NewGuid().ToString();

  public string Get() => _correlationId;

  public void Set(string correlationId) {
    if (!string.IsNullOrWhiteSpace(correlationId)) {
      _correlationId = correlationId;
    }
  }
}

We need to add the ICorrelationIdProvider to the application service collection, so we can use it throughout our application. To do this, we can either create an extension method or directly add it to the service collection when initializing the service collection. In this article, we will be using an extension method, to make things a bit neater.

Since the correlation ID would be generated per request, we need to inject the correlation ID provider service as a scoped service. This way, we will insure that the same instance of correlation Id provider is used through the various services and components during the lifecycle of the request.

public static class AddCorrelationIdServiceExtension {
  public static IServiceCollection AddCorrelationIdService(this IServiceCollection services) {
    return services.AddScoped<ICorrelationIdProvider, CorrelationIdImp>();
  }
}

Now we can add the correlation ID provider to the application’s service collection:

services.AddCorrelationIdService();

Next, we need to create a middleware that will intercept HTTP requests and analyze them for correlation ID in their header. By default, the correlation ID is expected to be in the X-Correlation-Id header of the request.  

The middleware will check for the correlation ID in the request header, if it exists, it will save it in the correlation ID provider instance, otherwise, it will generate a new correlation ID for it.

public class CorrelationIdMiddleware {
  private readonly RequestDelegate _next;
  private
  const string _correlationIdHeader = "X-Correlation-Id";

  public CorrelationIdMiddleware(RequestDelegate next) {
    _next = next;
  }

  public async Task InvokeAsync(HttpContext context, ICorrelationIdProvider correlationIdProvider) {
    // get or generate the request correlation id
    var requestCorrelationId = GetCorrelationId(context, correlationIdProvider);

    // add the correlation id to the http response header
    AddCorrelationIdHeaderToResponse(context, requestCorrelationId);

    await _next(context);
  }

  private string GetCorrelationId(HttpContext context, ICorrelationIdProvider correlationIdProvider) {
    if (context.Request.Headers.TryGetValue(_correlationIdHeader, out
        var existingCorrelationId)) {
      correlationIdProvider.Set(existingCorrelationId);
      return existingCorrelationId;
    }
    return correlationIdProvider.Get();
  }

  private static void AddCorrelationIdHeaderToResponse(HttpContext context, string correlationId) {
    context.Response.OnStarting(() => {
      context.Response.Headers.Add(_correlationIdHeader, new [] {
        correlationId
      });
      return Task.CompletedTask;
    });
  }
}

The next step is to add the middleware class to the application pipeline:

app.UseMiddleware<CorrelationIdMiddleware>();

And that’s it! we should be able to work with correlation ID anywhere in the application.