Search code examples
c#scopeintegration-testingstartup

Startup class: how to add scoped service and middleware


I am trying to add correlationid to request, and track them everywhere.

I have the following lines in the startup class:

services.AddScoped<ICorrelationIdGenerator, CorrelationIdGenerator>();
// ... other code
app.AddCorrelationIdMiddleware();

Then I have the following:

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

    public string Get() => _correlationId;

    public void Set(string correlationId)
    {
        _correlationId = correlationId;
    }
}
public static IApplicationBuilder AddCorrelationIdMiddleware(this IApplicationBuilder applicationBuilder)
        => applicationBuilder.UseMiddleware<CorrelationIdMiddleware>();
public class CorrelationIdMiddleware
{
    private readonly RequestDelegate _next;

    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(HttpHeaderConstants.CORRELATIONID, 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(HttpHeaderConstants.CORRELATIONID, new[] { correlationId.ToString() });
            return Task.CompletedTask;
        });
    }
}

The problem is mainly that is breaking existing tests and I have no idea how to fix them. The tests inherit from IntegrationTestBase<Startup>.

I added the following line to the IntegrationTestBase<Startup>:

services.AddScoped<ICorrelationIdGenerator, CorrelationIdGenerator>();

and I was expecting it to work.

Instead I got a bunch of errors that were not before the added functionality and

Cannot consume scoped service

from singleton x. Which x is the database that has nothing to do with the new functionality.


Solution

  • as @Stuartd has said in his comments, what I was trying to do was not possible due to their live times.

    Solution: changed the singleton to be injected