首页 > 解决方案 > 将 HTTP 消息处理程序添加到所有 HTTP 客户端

问题描述

我有一个名为 的 HTTP 消息处理程序AddHeadersHandler,它扩展System.Net.Http.DelegatingHandler并且我需要将它添加到所有当前和未来的HttpClient实例,包括类型化、命名和非命名客户端。

我知道我可以.AddHttpMessageHandler<AddHeadersHandler>()为特定客户端添加处理程序,但是如何将其添加到所有客户端?

// AddHeadersHandler.cs
public class AddHeadersHandler: DelegatingHandler
{
    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        request.Headers.TryAddWithoutValidation("X-Correlation-Id", Guid.NewGuid.ToString());

        return base.SendAsync(request, cancellationToken);
    }
}
// Startup.cs
services
    .AddHttpContextAccessor()
    .AddTransient<AddHeadersHandler>();
services
    .AddHttpClient<MyClient>()
    .AddHttpMessageHandler<AddHeadersHandler>(); // I don't want to specify this for each client.
// MyClient.cs
public class MyClient
{
    public HttpClient HttpClient { get; }

    public MyClient(HttpClient httpClient)
    {
        HttpClient = httpClient;
    }

    public async Task GetTest()
    {
        await HttpClient.GetAsync("https://localhost:5001/test"); // This should have headers attached.
    }
}

标签: c#asp.net-core.net-coredotnet-httpclient

解决方案


可以通过配置所有命名选项HttpClientFactoryOptions来完成。我们需要提供一个委托,其中将包括您的处理程序到属性列表。HttpMessageHandlerBuilderActionsAdditionalHandlers

使用选项模式有多种方法可以做到这一点。

1. 使用 .AddSingleton() ❌</h1>

如果您的处理程序有任何依赖项(例如IHttpContextAccessor,获取当前相关 id),我们希望使用依赖项注入来解决它。

我们可以使用OptionsBuilder API通过依赖注入来获取所需的处理程序。不幸的是,OptionsBuilder API 并没有像这样提供为所有命名实例配置选项的方法.ConfigureAll

幸运的是,我们可以通过注册一个工厂方法来获得我们需要的东西IConfigureOptions<HttpClientFactoryOptions>

// Startup.cs
services.AddSingleton<IConfigureOptions<HttpClientFactoryOptions>>(provider =>
{
    // When name is null, it will be used for all configurations.
    return new ConfigureNamedOptions<HttpClientFactoryOptions>(name: null, options =>
    {
        options.HttpMessageHandlerBuilderActions.Add(builder =>
        {
            // Here we have access to ServiceProvider to get an instance of the handler.
            builder.AdditionalHandlers.Add(provider.GetRequiredService<AddHeadersHandler>());
        });
    });
});

2. 使用 .ConfigureAll() ✔️

以下改进的答案受到LostInComputer的启发。

添加.ConfigureAll您的Startup.csIServiceProvider通过构建器对象使用,如下所示:

services.ConfigureAll<HttpClientFactoryOptions>(options =>
{
    options.HttpMessageHandlerBuilderActions.Add(builder =>
    {
        builder.AdditionalHandlers.Add(builder.Services.GetRequiredService<AddHeadersHandler>());
    });
});

推荐阅读