.NET 6 - Web API Correlation Id 🔗
Tags: dotnet, api, architecture, tutorial
Published: 2022-09-03 07:55:33

In this article we will be cover Correlation Id in APIs and howe can add them to our .NET Web API and utilise them.

You can watch the full video on youtube:
{% embed https://youtu.be/y0CQmwRllvQ %}

And find the full source code on github:
https://github.com/mohamadlawand087/Api-Correlation

A Correlation ID is a unique identifier value that is attached to requests and messages that allow reference to a particular transaction or event chain. Attaching a Correlation ID to a request is arbitrary.

Create a new project

```bash
dotnet new webapi -n CorrerlationApi
```

Once we open it in VS Code, we need to add a new folder in the root directory called Configurations

Inside the Configurations folder we need to create a new folder called interfaces and inside the interface we need to create an interface called ICorrelationIdGenerator

```csharp
namespace CorrerlationApi.Configurations.Interfaces;

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

Now inside the Configuration folder we need to create the CorrelationIdGenerator class

```csharp
using ApiCorrolation.Configurations.Interfaces;

namespace CorrerlationApi.Configurations;

public class CorrelationIdGenerator : ICorrelationIdGenerator
{
    private string _correlationId = Guid.NewGuid().ToString();

    public string Get() => _correlationId;

    public void Set(string correlationId) { 
			_correlationId = correlationId;
		}
}
```

Since the CorrolationId would be generated per request, not across the lifetime of the application we need to inject the CorrelationIdGenerator as a Scoped service rather then a singleton one

To register the Correlation Id we can utilise an extension method so inside the Configuration folder we will create a new folder called Services

Inside the Services folder we create a new class called ServiceCollectionExtensions and we add the following

```csharp
using CorrerlationApi.Configurations.Interfaces;
using CorrerlationApi.Configurations;

namespace CorrerlationApi.Services;

public static class ServiceCollectionExtensions
{
    public static IServiceCollection AddCorrelationIdGeneratorService(this IServiceCollection services)
    {
        services.AddScoped<ICorrelationIdGenerator, CorrelationIdGenerator>();

        return services;
    }
}
```

The next step is attach the services to the application startup in the program.cs

```csharp
builder.Services.AddCorrelationIdGeneratorService();
```

Now that our CorrelationId services are able to be injected scoped, we need to create the middleware which is responsible for catching the incoming request, analysing it for correlation-id in the header

inside the root directory we create a new folder called Helpers and inside the Helpers folder we create a new class called CorrelationIdMiddleare.cs and we add the following

```csharp
using CorrerlationApi.Configurations.Interfaces;
using Microsoft.Extensions.Primitives;

namespace CorrerlationApi.Helpers;

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

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

    public async Task Invoke(HttpContext context, ICorrelationIdGenerator correlationIdGenerator)
    {
        var correlationId = GetCorrelationId(context, correlationIdGenerator);
        AddCorrelationIdHeaderToResponse(context, correlationId);

        await _next(context);
    }

    private static StringValues GetCorrelationId(HttpContext context, ICorrelationIdGenerator correlationIdGenerator)
    {
        if(context.Request.Headers.TryGetValue(_correlationIdHeader, out var correlationId))
        {
            correlationIdGenerator.Set(correlationId);
            return correlationId;
        }
        else
        {
            return correlationIdGenerator.Get();
        }
    }

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

The next step is injecting the middleware in the application startup inside the Services folder we create a new class called ApplicationBuilderExtensions

 

```csharp
using CorrerlationApi.Helpers;

namespace CorrerlationApi.Services;

public static class ApplicationBuilderExtensions
{
    public static IApplicationBuilder AddCorrelationIdMiddleware(this IApplicationBuilder applicationBuilder)
        => applicationBuilder.UseMiddleware<CorrelationIdMiddleware>();
}
```

And we need to update the program.cs with the following

```csharp
app.AddCorrelationIdMiddleware();
```

Lastly let us test the functionality in our controller, by updating the WeatherForcastController with the following

```csharp
using CorrerlationApi.Configurations.Interfaces;
using CorrerlationApi.Services;
using Microsoft.AspNetCore.Mvc;

namespace CorrerlationApi.Controllers;

[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
    private static readonly string[] Summaries = new[]
    {
        "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
    };

    private readonly ICorrelationIdGenerator _correlationIdGenerator;

    private readonly ILogger<WeatherForecastController> _logger;

    public WeatherForecastController(
        ILogger<WeatherForecastController> logger,
        ICorrelationIdGenerator correlationIdGenerator)
    {
        _logger = logger;
         _correlationIdGenerator = correlationIdGenerator;
    }

    [HttpGet(Name = "GetWeatherForecast")]
    public IEnumerable<WeatherForecast> Get()
    {
        _logger.LogInformation("CorrelationId {correlationId}: Processing weather forecast request",
            _correlationIdGenerator.Get());
            
        return Enumerable.Range(1, 5).Select(index => new WeatherForecast
        {
            Date = DateTime.Now.AddDays(index),
            TemperatureC = Random.Shared.Next(-20, 55),
            Summary = Summaries[Random.Shared.Next(Summaries.Length)]
        })
        .ToArray();
    }
}
```

Please comment any of your questions and thank you for reading.