Search code examples
c#asp.net-coreflurl

How to correctly DI HttpClient into FlurlClient?


Registering a custom message handler doesnt seem to work with FlurlClient.

    .. other setup logic
    /// <summary>
    /// Configures the application services.
    /// </summary>
    /// <param name="services">The service collection.</param>
    public override void ConfigureServices(IServiceCollection services)
    {
        services.AddTransient<ConsoleCorrelationIdHandler>();
        this.AddHttpClient<ICatalogService, CatalogService>(services, "http://httpbin.org");

    }

    private void AddHttpClient<TClient, TImplementation>(IServiceCollection services, string url = null)
        where TClient : class
        where TImplementation : class, TClient
        => services.AddHttpClient<TClient, TImplementation>(client =>
        {
            if (!string.IsNullOrWhiteSpace(url))
                client.BaseAddress = new Uri(url);
        })
            .AddHttpMessageHandler<ConsoleCorrelationIdHandler>(); // Appends CorrelationId to all outgoing HTTP requests.

Here i register a new HttpClient with a ConsoleCorrelationIdHandler, which adds a correlation id header to all outgoing requests.

public class CatalogService : ICatalogService
{
    private readonly IFlurlClient _httpClient;

    public CatalogService(HttpClient httpClient)
    {
        _httpClient = new FlurlClient(httpClient);
    }

    public async Task GetSomething()
    {
        var x = await this._httpClient.BaseUrl
            .AppendPathSegment("get")
            .GetJsonAsync();
        Console.WriteLine(JsonConvert.SerializeObject(x)); // Doesnt have CorrelationId header, which should have been added by handler.
    }
}

Now when GetSomething gets called, the IFlurlClient does have the base url of the registered httpclient, but the message handler doesn't get called.


Solution

  • Let's break down your fluent call and see what's happening:

    _httpClient.BaseUrl
    

    You now have a reference to a string. You've lost your reference to the client here.

    .AppendPathSegment("get")
    

    Here you're calling a string extension method that creates a Flurl.Url object and appends get to the path.

    .GetJsonAsync();
    

    Here you're calling an extension method on Url that creates a FlurlRequest and calls its GetJsonAsync method. With no reference back to the client you want to use, it's going to look for one using the registered FlurlClientFactory. Not finding one there, it'll create a new one.

    In short, you lost your reference to your FlurlClient right at the beginning of that call.

    Here's how to fix it:

    var x = await this._httpClient
        .Request("get")
        .GetJsonAsync();