asp.net-core - 单例 HttpClient 是否在 X 分钟后接收到新的 HttpMessageHandler

标签 asp.net-core dependency-injection httpclient httpclientfactory

我在工厂注册我的 HttpClient:

services.AddHttpClient<ICatalogService, CatalogService>()
    .SetHandlerLifetime(TimeSpan.FromMinutes(2));

这个 ICatalogService 是通过单例服务中的构造函数注入(inject)的。

我会在 2 分钟后在内部收到一个新的 HttpMessageHandler 还是仅当 ICatalogService 在 2 分钟后注入(inject)到非单例服务中时?

基本上,当包装 HttpHandler 时,内部 HttpMessageHandler 是否也会过期 用作单例?

最佳答案

does the internal HttpMessageHandler expires also when the wrapping HttpHandler is used as a Singleton?

警告:通过 Singletons 保持 HttpClient 实例事件是安全的。

配置的 HttpMessageHandler 实例将在两分钟后过期。在到期日期之后 创建的任何 HttpClient 都将获得包含新到期日期的新 HttpMessageHandler。但这对保持事件状态的 HttpClient 实例没有帮助。

重要 HttpClient 将一直使用相同的 HttpMessageHandler,因此, not respect DNS changes .只有新的 HttpMessageHandler 实例才会看到 DNS 更新。

这意味着只要您保持 HttpClient 处于事件状态,HttpClient 就会错过 DNS 更改,这就是为什么 HttpClient 实例应该只短期居住。创建和清理 HttpClient 实例的成本非常低,只要您重用底层的 HttpMessageHandler 实例(这是基础架构为您做的)。

不幸的是,在您的情况下,您的 HttpClient 被注入(inject)到 CatalogService 中,后者被注入(inject)到 Singleton 消费者中。 Singleton 使 CatalogService 保持事件状态,因此间接使 HttpClient 在应用程序运行期间保持事件状态——您的 HttpClient 现在是 Captive Dependency .

您遇到的是新 .NET Core IHttpClientFactory 基础结构中的一个不幸的设计缺陷。我认为这是一个缺陷,因为 IMO 基础设施应该阻止你持有 HttpClient 实例俘虏,例如通过将客户端(您的 CatalogService)注册为 Scoped。我 reported this issue早在 2019 年 1 月。Microsoft 已经承认了这个问题,但在撰写本文时,还没有可用的解决方案。

由于还没有解决方案,您必须非常小心,不要让 HttpClient 作为 Captive Dependency 保持事件状态。这意味着您不能将其注入(inject) Singleton 消费者(即使是间接消费者)。

防止这种情况的一个好方法是将客户端(您的 CatalogService)注册为 Scoped。这允许框架的配置系统验证它是否被注入(inject)到 Singleton 中。但是由于没有对此的直接支持,您将不得不手动进行此注册,例如使用以下扩展方法:

public static IHttpClientBuilder AddTypedClientScoped<TClient>(
  this IHttpClientBuilder builder)
  where TClient : class
{
    ...
    builder.Services.AddScoped<TClient>(s =>
    {
        var httpClientFactory = s.GetRequiredService<IHttpClientFactory>();
        var httpClient = httpClientFactory.CreateClient(builder.Name);
        var factory = s.GetRequiredService<ITypedHttpClientFactory<TClient>>();
        return factory.CreateClient(httpClient);
    });

    return builder;
}

启动 ASP.NET Core 网站时 while debugging ,框架将为您验证范围,这会在客户端注入(inject)单例时导致异常。

但请注意,使用此扩展方法不会检测所有捕获的 HttpClient 实例。这是因为在 ASP.NET Core 中的某些地方,组件被注册为 Transient,但在应用程序运行期间仍会保持事件状态。一个这样的例子是 hosted services . AddHostedService 扩展方法就是这样的例子。托管服务注册为 Transient,同时作为 Singleton 保持事件状态。在我看来,还有另一个设计缺陷。但这意味着您在直接或间接将 HttpClient 实例注入(inject)托管服务时应该小心。

关于asp.net-core - 单例 HttpClient 是否在 X 分钟后接收到新的 HttpMessageHandler,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68820007/

相关文章:

c# - ASP.NET Core WebApi

带有水果的 C++ 依赖注入(inject)

dependency-injection - 在struts2 Action 中注入(inject)EJB?

c# - 带有 CancellationToken 的 HttpClient 在 Xamarin 应用程序中不起作用

java - 如何查找 HTML 文件的大小和数据传输速率

asp.net-core - EF Core 2.1 中数据库 View 的 Scaffold-DbContext(查询类型)

c# - 在 Razor 页面中动态更改按钮标签文本

java - Dagger 2 和接口(interface)实现

android - HttpClient 不在 galaxy s2 上存储 cookie

entity-framework - db.database.ExecuteSQLCommand 等效于 EF 7