在 C# 中,如何为多个服务重用 HttpClient?
In C#, How can I reuse an HttpClient for multiple services?
我创建了一个 C# 微服务,它提供了几个不同(但相关)的功能。
我现在正在为客户端创建一个 C# Nuget 包,它将帮助其他 C# 微服务利用该微服务。这将包括一个服务集合扩展 class 以方便将客户端添加到这些微服务。
为了分离关注点,在客户端中,我将功能分为三个 classes:
- SalesforceCacheQuerier
- SalesforceCacheSyncDataManipulator
- SalesforceCacheAsyncDataManipulator
每一个都需要调用同一个服务器。
作为 niave 的第一个实现,我编写了这个方法:
public static IServiceCollection AddSalesforceClients(this IServiceCollection services)
{
services.AddTransient<SalesforceCacheAuthenticationHandler>();
ConfigureClient(services.AddHttpClient<ISalesforceCacheQuerier, SalesforceCacheQuerier>());
ConfigureClient(services.AddHttpClient<ISalesforceCacheSyncDataManipulator, SalesforceCacheSyncDataManipulator>());
ConfigureClient(services.AddHttpClient<ISalesforceCacheAsyncDataManipulator, SalesforceCacheAsyncDataManipulator>());
return services;
}
private static IHttpClientBuilder? ConfigureClient(IHttpClientBuilder? clientBuilder)
=> clientBuilder.ConfigureHttpClient(ConfigureClient)
.ConfigurePrimaryHttpMessageHandler(() => new SocketsHttpHandler())
.AddHttpMessageHandler<SalesforceCacheAuthenticationHandler>();
private static void ConfigureClient(IServiceProvider provider, HttpClient client)
{
SalesforceCacheSettings? settings = provider.GetRequiredService<SalesforceCacheSettings>();
client.BaseAddress = new Uri(settings.BaseUrl, settings.ApiEndpoint);
client.DefaultRequestHeaders.ExpectContinue = true;
}
但是,这会生成三个独立的 HttpClient 并使用于提供 Jwt 令牌的“身份服务器”的流量增加三倍。
如何重构它以仅创建和重用一个 HttpClient?
您可以使用 HttpClientFactory 并将其注入 ConfigureServices
像 services.AddHttpClient();
稍后无论您需要客户端 object 只需在构造函数中提供 IHttpClientFactory httpClientFactory
,您就可以通过要求工厂创建客户端来访问客户端 object。
HttpClient = HttpClientFactory.CreateClient();
以这种方式。
以防万一你想为客户端保留身份验证并重新使用它。我建议为每种请求类型维护一个字典。
var HttpClients = new Dictionary<string, HttpClient>();
HttpClients.Add(SalesforceCacheQuerierKey, SalesforceCacheQuerierClient);
//假设所有与 auth 相关的 headers 都添加到此客户端 object //SalesforceCacheQuerierClient
并从启动级别传递这些。
我需要的是这样的:
services.AddHttpClient(SALESFORCE_CACHE_CLIENT, (provider, client) =>
{
SalesforceCacheClientSettings? settings = provider.GetRequiredService<SalesforceCacheClientSettings>();
client.BaseAddress = new Uri(settings.BaseUrl, settings.ApiEndpoint);
client.DefaultRequestHeaders.ExpectContinue = true;
})
.AddHttpMessageHandler<SalesforceCacheAuthenticationHandler>();
services.AddHttpClient<ISalesforceCacheQuerier, SalesforceCacheQuerier>(SALESFORCE_CACHE_CLIENT);
services.AddHttpClient<ISalesforceCacheSyncDataManipulator, SalesforceCacheSyncDataManipulator>(SALESFORCE_CACHE_CLIENT);
services.AddHttpClient<ISalesforceCacheAsyncDataManipulator, SalesforceCacheAsyncDataManipulator>(SALESFORCE_CACHE_CLIENT);
我创建了一个 C# 微服务,它提供了几个不同(但相关)的功能。
我现在正在为客户端创建一个 C# Nuget 包,它将帮助其他 C# 微服务利用该微服务。这将包括一个服务集合扩展 class 以方便将客户端添加到这些微服务。
为了分离关注点,在客户端中,我将功能分为三个 classes:
- SalesforceCacheQuerier
- SalesforceCacheSyncDataManipulator
- SalesforceCacheAsyncDataManipulator
每一个都需要调用同一个服务器。
作为 niave 的第一个实现,我编写了这个方法:
public static IServiceCollection AddSalesforceClients(this IServiceCollection services)
{
services.AddTransient<SalesforceCacheAuthenticationHandler>();
ConfigureClient(services.AddHttpClient<ISalesforceCacheQuerier, SalesforceCacheQuerier>());
ConfigureClient(services.AddHttpClient<ISalesforceCacheSyncDataManipulator, SalesforceCacheSyncDataManipulator>());
ConfigureClient(services.AddHttpClient<ISalesforceCacheAsyncDataManipulator, SalesforceCacheAsyncDataManipulator>());
return services;
}
private static IHttpClientBuilder? ConfigureClient(IHttpClientBuilder? clientBuilder)
=> clientBuilder.ConfigureHttpClient(ConfigureClient)
.ConfigurePrimaryHttpMessageHandler(() => new SocketsHttpHandler())
.AddHttpMessageHandler<SalesforceCacheAuthenticationHandler>();
private static void ConfigureClient(IServiceProvider provider, HttpClient client)
{
SalesforceCacheSettings? settings = provider.GetRequiredService<SalesforceCacheSettings>();
client.BaseAddress = new Uri(settings.BaseUrl, settings.ApiEndpoint);
client.DefaultRequestHeaders.ExpectContinue = true;
}
但是,这会生成三个独立的 HttpClient 并使用于提供 Jwt 令牌的“身份服务器”的流量增加三倍。
如何重构它以仅创建和重用一个 HttpClient?
您可以使用 HttpClientFactory 并将其注入 ConfigureServices
像 services.AddHttpClient();
稍后无论您需要客户端 object 只需在构造函数中提供 IHttpClientFactory httpClientFactory
,您就可以通过要求工厂创建客户端来访问客户端 object。
HttpClient = HttpClientFactory.CreateClient();
以这种方式。
以防万一你想为客户端保留身份验证并重新使用它。我建议为每种请求类型维护一个字典。
var HttpClients = new Dictionary<string, HttpClient>();
HttpClients.Add(SalesforceCacheQuerierKey, SalesforceCacheQuerierClient);
//假设所有与 auth 相关的 headers 都添加到此客户端 object //SalesforceCacheQuerierClient
并从启动级别传递这些。
我需要的是这样的:
services.AddHttpClient(SALESFORCE_CACHE_CLIENT, (provider, client) =>
{
SalesforceCacheClientSettings? settings = provider.GetRequiredService<SalesforceCacheClientSettings>();
client.BaseAddress = new Uri(settings.BaseUrl, settings.ApiEndpoint);
client.DefaultRequestHeaders.ExpectContinue = true;
})
.AddHttpMessageHandler<SalesforceCacheAuthenticationHandler>();
services.AddHttpClient<ISalesforceCacheQuerier, SalesforceCacheQuerier>(SALESFORCE_CACHE_CLIENT);
services.AddHttpClient<ISalesforceCacheSyncDataManipulator, SalesforceCacheSyncDataManipulator>(SALESFORCE_CACHE_CLIENT);
services.AddHttpClient<ISalesforceCacheAsyncDataManipulator, SalesforceCacheAsyncDataManipulator>(SALESFORCE_CACHE_CLIENT);