Skip to content

Auto-register IHttpMessageHandlerBuilderFilter for IHttpClientFactory in TUnit.AspNetCore #5590

@thomhurst

Description

@thomhurst

Problem

TestWebApplicationFactory<T> and TracedWebApplicationFactory<T> only inject ActivityPropagationHandler and TUnitTestIdHandler into the HttpClient instances they create via CreateDefaultClient. Any HttpClient resolved inside the SUT through IHttpClientFactory (services.AddHttpClient<T>(), named clients, typed clients) is unaffected.

Consequences:

  • Outbound HTTP calls from the SUT to downstream services do not carry the test's traceparent or baggage headers.
  • Downstream spans cannot be correlated back to the originating test.
  • Users must remember to call .AddHttpMessageHandler<ActivityPropagationHandler>() on every client registration.

Proposal

Ship an IHttpMessageHandlerBuilderFilter in TUnit.AspNetCore that prepends ActivityPropagationHandler and TUnitTestIdHandler to every IHttpClientFactory builder pipeline. Register it automatically from TestWebApplicationFactory.ConfigureWebHost:

internal sealed class TUnitHttpClientFilter : IHttpMessageHandlerBuilderFilter
{
    public Action<HttpMessageHandlerBuilder> Configure(Action<HttpMessageHandlerBuilder> next) =>
        builder =>
        {
            next(builder);
            builder.AdditionalHandlers.Insert(0, new ActivityPropagationHandler());
            builder.AdditionalHandlers.Insert(1, new TUnitTestIdHandler());
        };
}

// In TestWebApplicationFactory.ConfigureWebHost
services.TryAddEnumerable(
    ServiceDescriptor.Singleton<IHttpMessageHandlerBuilderFilter, TUnitHttpClientFilter>());

Considerations

  • Handlers must be safe to share across concurrent requests (they already are).
  • Do not register when the SUT is under a real process (non-test) — gate on TestContext.Current is not null or on a registration-time flag set by the factory.
  • Provide opt-out via WebApplicationTestOptions.AutoPropagateHttpClientFactory = false for users who do their own instrumentation.
  • This does not help WebApplicationFactory.CreateClient() (handled by TestWebApplicationFactory overrides) or raw new HttpClient() instances (cannot be intercepted).

Related

  • Discussion HTML report generation failed #5479.
  • Covers outbound calls from SUT to external services; handler-chain injection into WAF's own client is already done by TestWebApplicationFactory.

Documentation

When this lands, update:

  • docs/docs/examples/opentelemetry.md — in the "My HTTP calls don't carry the test trace" troubleshooting section, remove the manual .AddHttpMessageHandler<ActivityPropagationHandler>() recipe (now automatic for IHttpClientFactory clients).
  • docs/docs/guides/distributed-tracing.md — same for the IHttpClientFactory clients limitation entry.
  • docs/docs/examples/aspnet.md — list this auto-behavior in the Quick Start.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions