2
votes

I have 3 microservices and try to create correlation id to keep track of the every log issues. If corrID is not null when request comes, then I set it. If not, it is generated. And then passed to the next. I want to see corrId for 3 services' logs. If I used the code below everything works well. But swagger does not work.

Exception: headers are read-only response has already started.

 public async Task Invoke(HttpContext context)
            {
                string key = context.Request.Headers.Keys.FirstOrDefault(n => n.Equals("Correlation-ID"));

                var corrID = context.RequestServices.GetService<CorrelationID_Global>();

                if (corrID != null)
                {
                    if (!string.IsNullOrWhiteSpace(key))
                    {

                        corrID.ID = context.Request.Headers[key].ToString();
                    }
                    else
                    {
                        corrID.ID = Guid.NewGuid().ToString();

                    }
                }

                await _next(context);

                if (!string.IsNullOrWhiteSpace(corrID?.ID))
                {               
                        context.Response.Headers.Add("Correlation-ID", corrID.ID);
                }

            }

To solve swagger problem, I change the last if statement using this link: Add Response Headers to ASP.NET Core Middleware

  if (!string.IsNullOrWhiteSpace(corrID?.ID))
    {
        context.Response.OnStarting((state) =>
        {
            context.Response.Headers.Add("Correlation-ID", corrID.ID);
            return Task.FromResult(0);
        },null);
    }

However, this time I cannot see correlation-Id at responses' log of services.Thus corrID of requests' log changes as usual. How can I handle this problem? Thanks.

1

1 Answers

4
votes

The correct way is to register context.Response.OnStarting callback before await _next(context); as one of the next middlewares in pipeline will start the response.

In other words, with the current implementation, your OnStarting callback is not fired as is registered too late. Change middleware code to

if (!string.IsNullOrWhiteSpace(corrID?.ID))
{
    context.Response.OnStarting((state) =>
    {
        context.Response.Headers.Add("Correlation-ID", corrID.ID);
        return Task.FromResult(0);
    }, context);
}

await _next(context);