如何正确地将 HttpClient DI 成 FlurlClient?

How to correctly DI HttpClient into FlurlClient?

注册自定义消息处理程序似乎不适用于 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.

在这里,我使用 ConsoleCorrelationIdHandler 注册了一个新的 HttpClient,它向所有传出请求添加了一个关联 ID header。

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.
    }
}

现在,当调用 GetSomething 时,IFlurlClient 确实具有已注册 httpclient 的基础 url,但不会调用消息处理程序。

让我们分解你的流利调用,看看发生了什么:

_httpClient.BaseUrl

您现在有一个字符串的引用。您在这里丢失了对客户的引用。

.AppendPathSegment("get")

此处调用的是创建 Flurl.Url 对象并将 get 附加到路径的字符串扩展方法。

.GetJsonAsync();

此处您在 Url 上调用一个扩展方法,它创建一个 FlurlRequest 并调用它的 GetJsonAsync 方法。由于没有对您要使用的客户端的引用,它将使用已注册的 FlurlClientFactory 寻找一个客户端。在那里找不到,它会创建一个新的。

简而言之,您在调用开始时丢失了对 FlurlClient 的引用。

修复方法如下:

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