由 HttpClientFactory 创建的 HttpClient 实例是不是应该被释放?
Posted
技术标签:
【中文标题】由 HttpClientFactory 创建的 HttpClient 实例是不是应该被释放?【英文标题】:Should HttpClient instances created by HttpClientFactory be disposed?由 HttpClientFactory 创建的 HttpClient 实例是否应该被释放? 【发布时间】:2018-11-27 11:00:24 【问题描述】:所以,我在我的 Startup.cs 中使用服务集合注册了一个命名客户端:
services.AddHttpClient(someServiceName,
client => client.BaseAddress = baseAddress);
现在可以从我的服务提供商那里注入一个IHttpClientFactory
。
使用这个IHttpClientFactory
,我想出了一个客户端实例:
var client = httpClientFactory.CreateClient(someServiceName)
曾几何时,在处理HttpClient
实例时必须非常小心,因为它是rarely the right thing to do。
但是,现在我们有了HttpClientFactory
,这还重要吗?这个client
是否应该/可以无忧处理?例如
using (var httpClient = httpClientFactory.CreateClient(someServiceName))
using (var response = await httpClient.PostAsync(somePath, someData))
var content = await response.Content.ReadAsAsync<SomeResponse>();
//...
【问题讨论】:
查看这篇文章,它解释了工厂如何处理客户stevejgordon.co.uk/introduction-to-httpclientfactory-aspnetcore @Nkosi 是的,我读过。但是,我找到了一些看起来很像我的问题中最后一个 sn-p 的代码,我想知道是否需要修复它。 【参考方案1】:没有。您不应该处置您的客户。更一般地说,您不应该处理通过 DI 容器检索到的 anything,在 ASP.NET Core 中,默认情况下该容器是服务集合。生命周期由 DI 容器管理,因此如果您处置客户端,但稍后将其注入某些东西,您将获得 ObjectDisposedException
。让容器处理处置。
这实际上是与IDisposable
类的常见混淆。如果您的类本身拥有依赖项,则您应该亲自实现IDisposable
。如果它的所有依赖项都注入,则不应实现IDisposable
,因为它不拥有任何需要处理的东西。同样,您不应该处理注入到您的类中的任何东西,因为它不拥有这些依赖项。只处理你特别新的东西。如果您没有看到关键字 new
,您可能不应该丢弃。
【讨论】:
这有点令人困惑,因为客户端不是通过 DI 容器检索的。 factory 是通过 DI 容器检索的。 但是 httpClientFactory.CreateClient(someServiceName) 中的命名似乎暗示你是新的,所以这是令人困惑的部分。我和@KierenJohnstone 在一起 资源是否被更新并不重要,重要的是你是否控制它的生命周期。在工厂的情况下,工厂进行实例化并控制生命周期,而不是您。这才是重点。只处置属于您的资源。 @ChrisPratt 如果 C# 或 .NET 包含某种对象生命周期和所有权语义以防止这种混淆,您是否同意这不会成为问题?甚至是简单的东西,例如接口(例如IDisposableHahahNotReally
)或通过智能指针类型对象引用对象,例如OwnedObject<T>.Instance
和 BorrowedObject<T>.Value
)。
@ChrisPratt 我认为这并不重要。我记得在 ASP.NET 存储库上的 GitHub 问题中读到它是 HttpClientHandler 不能被释放。当您处理 HttpClient(由上述工厂创建)时,处理程序“告诉”客户端在处理它时不要处理它。所以,像这样的代码完全没有问题using (var client = _httpClientFactory.CreateClient())
。 (我认为):)【参考方案2】:
不需要调用Dispose
方法,但如果出于某些原因需要,您仍然可以调用它。
证明:HttpClient and lifetime management
不需要处理客户。 Disposal 取消传出请求并保证在调用 Dispose 后不能使用给定的 HttpClient 实例。 IHttpClientFactory 跟踪和释放 HttpClient 实例使用的资源。 HttpClient 实例通常可以被视为不需要处理的 .NET 对象。
查看source of DefaultHttpClientFactory
:
public HttpClient CreateClient(string name)
if (name == null)
throw new ArgumentNullException(nameof(name));
var handler = CreateHandler(name);
var client = new HttpClient(handler, disposeHandler: false);
var options = _optionsMonitor.Get(name);
for (var i = 0; i < options.HttpClientActions.Count; i++)
options.HttpClientActions[i](client);
return client;
HttpMessageHandler
的实例存储了HttpClient
的非托管资源。在经典场景中,HttpClient
创建HttpMessageHandler
的实例,并在自己处理的同时处理它。
您可以在上面的代码中看到HttpClient
的不同实例共享HttpMessageHandler
的单个实例并且不释放它(disposeHandler: false
)。
所以,HttpClient.Dispose
的调用没有任何作用。但这并不危险。
【讨论】:
以上是关于由 HttpClientFactory 创建的 HttpClient 实例是不是应该被释放?的主要内容,如果未能解决你的问题,请参考以下文章
.NET Core HttpClientFactory+Consul实现服务发现
如何在 .NET Core 中使用 HttpClientHandler 和 HttpClientFactory
如何使用 Moq 在 .NET Core 2.1 中模拟新的 HttpClientFactory
asp.net core 使用HttpClientFactory Polly实现熔断降级