X 分钟后 Singleton HttpClient 是否收到新的 HttpMessageHandler

rud*_*ter 3 dependency-injection httpclient asp.net-core httpclientfactory

我在工厂中注册我的 HttpClient:

services.AddHttpClient<ICatalogService, CatalogService>()
    .SetHandlerLifetime(TimeSpan.FromMinutes(2));
Run Code Online (Sandbox Code Playgroud)

此 ICatalogService 通过构造函数注入到单例服务中。

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

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

Ste*_*ven 5

\n

当包装 HttpHandler 用作单例时,内部 HttpMessageHandler 也会过期吗?

\n
\n

警告:HttpClient通过单例保持实例活动并不安全

\n

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

\n

重要提示: 只要它存在,HttpClient就会继续使用它,因此,\n不尊重 DNS 更改。只有新实例才会看到 DNS 更新。HttpMessageHandlerHttpMessageHandler

\n

这意味着只要您保持HttpClient活动状态,HttpClient就会错过 DNS 更改,这就是HttpClient实例只能存活很短一段时间的原因。HttpClient只要您重用底层实例HttpMessageHandler(这就是基础设施为您所做的),创建和清理实例的成本就非常低。

\n

不幸的是,在您的情况下,您HttpClient被注入到CatalogService,而 被注入到Singleton消费者中。保持Singleton活动CatalogService状态,因此HttpClient在应用程序\xe2\x80\x94的持续时间内间接保持活动状态您HttpClient现在是Captive Dependency

\n

您遇到的是新的 .NET CoreIHttpClientFactory基础架构中的一个不幸的设计缺陷。我认为这是一个缺陷,因为 IMO 基础设施应该阻止您将HttpClient实例捕获,例如通过将客户端(您的CatalogService)注册为Scoped. 我早在 2019 年 1 月就报告了这个问题。微软已经承认了这个问题,但截至撰写本文时,还没有可用的解决方案。

\n

由于还没有解决方案,因此您必须非常小心,不要导致HttpClient作为 Captive Dependency 保持活动状态。这意味着您不能将其注入Singleton消费者(甚至是间接消费者)。

\n

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

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

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

\n

但请注意,使用此扩展方法不会检测所有捕获HttpClient实例。这是因为 ASP.NET Core 中的某些位置组件被注册为Transient在应用程序持续时间内仍保持活动状态。托管服务就是这样的案例之一。扩展AddHostedService方法就是这样的例子。Transient托管服务在保持活动状态时注册为Singleton。在我看来,这是另一个设计缺陷。但这意味着您在直接或间接将HttpClient实例注入托管服务时应该小心。

\n