Skip to content

HeaderPropagation middleware: MessageHandler throws when used outside of a request #12169

Open
@alefranz

Description

@alefranz

Describe the bug

The MessageHandler relies on the Middleware to initialize HeaderPropagationValues.Headers to detect misconfiguration. However this means the Messagehandler can not be used outside of an http request and currently throws:

System.InvalidOperationException: The HeaderPropagationValues.Headers property has not been initialized. If using this HttpClient as part of an http request, register the header propagation middleware by adding 'app.UseHeaderPropagation() in the 'Configure(...)' method. Otherwise, use HeaderPropagationProcessor.ProcessRequest() before using the HttpClient.

To Reproduce

Steps to reproduce the behavior:

Code example
public void ConfigureServices(IServiceCollection services)
{
    services
        .AddHttpClient("test")
        .AddHeaderPropagation();
    services.AddHostedService<SampleHostedService>();
}
public class SampleHostedService : IHostedService
{
    private readonly IHttpClientFactory _httpClientFactory;
    private readonly HeaderPropagationProcessor _headerPropagationProcessor;
    private readonly ILogger _logger;

    public SampleHostedService(IHttpClientFactory httpClientFactory, HeaderPropagationProcessor headerPropagationProcessor, ILogger<SampleHostedService> logger)
    {
        _httpClientFactory = httpClientFactory ?? throw new ArgumentNullException(nameof(httpClientFactory));
        _headerPropagationProcessor = headerPropagationProcessor ?? throw new ArgumentNullException(nameof(headerPropagationProcessor));
        _logger = logger ?? throw new ArgumentNullException(nameof(logger));
    }

    public Task StartAsync(CancellationToken cancellationToken)
    {
        return DoWorkAsync();
    }

    private async Task DoWorkAsync()
    {
        _logger.LogInformation("Background Service is working.");

        var client = _httpClientFactory.CreateClient("test");
        var result = await client.GetAsync("http://localhost:62013/forwarded");

        _logger.LogInformation("Background Service:\n{result}", result);
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        return Task.CompletedTask;
    }
}

Expected behavior

The HttpClient should work if used outside of a request or, if we don't wont to support this use case, the exception should be updated to explain that such use case is not supported..

Possible solutions

I had investigated possible solutions. Not sure what is your preferred options and if we are still in time to do breaking changes on this middleware.
Here are some options:

  1. Remove the check that throws the exception which means we would not be able anymore to detect misconfiguration. Can this be replaced with an analyzer?
    On top of the risk that the feature might not work due to misconfiguration, there is also the risk that having the valuefilter not execute (e.g. to set some headers with default values) when not called from outside a request can be unexpected.
  2. Update the exception message to also explain that a HttpClient with the HeaderPropagationMessageHandler can not be used outside of a request. This is not ideal as it means you end up duplicating your HttpClients configuration.
  3. Extract the functionality from the Middleware to a generic Processor that can be called outside a http request. This will not change the middleware behaviour, but will allow to explicitly call the Processor when consuming an HttpClient outside of a http request. Ideally this will also include changing the valueFactory to receive a headers collection instead of the HttpContext, so that headers can be passed in different scenarios, for example when consuming messages from a queue, however I guess this scenario is out of scope for a middleware. See draft PR HeaderPropagation: add support for hosted services #12170 . The main issue I see with this approach is that when the processor is used directly you must take extra care as you need a different async context per request.

Looking forward for your feedback.

Thank you,
Alessio

/cc @rynowak

Metadata

Metadata

Assignees

No one assigned

    Labels

    affected-fewThis issue impacts only small number of customersarea-middlewareIncludes: URL rewrite, redirect, response cache/compression, session, and other general middlewaresenhancementThis issue represents an ask for new feature or an enhancement to an existing oneseverity-majorThis label is used by an internal tool

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions