是否应处置由 HttpClientFactory 创建的 HttpClient 实例?

Should HttpClient instances created by HttpClientFactory be disposed?

所以,我已经在 Startup.cs:

中的服务集合中注册了一个命名客户端
services.AddHttpClient(someServiceName, 
                       client => client.BaseAddress = baseAddress);

现在可以从我的服务提供商那里注入 IHttpClientFactory

使用这个 IHttpClientFactory,我想出了一个客户端实例:

var client = httpClientFactory.CreateClient(someServiceName)

曾几何时,处理 HttpClient 个实例需要非常小心,因为它是 rarely the right thing to do

但是,现在我们有了HttpClientFactory,这还有什么关系吗? Should/Can这个client安心处置?例如

using (var httpClient = httpClientFactory.CreateClient(someServiceName))
using (var response = await httpClient.PostAsync(somePath, someData))
{
    var content = await response.Content.ReadAsAsync<SomeResponse>();
    //...
}

没有。你不应该处置你的客户。更一般地说,您不应该处理通过 DI 容器检索到的 任何东西,在 ASP.NET Core 中默认情况下它是服务集合。生命周期由 DI 容器管理,所以如果你处理掉客户端,但它后来被注入到某些东西中,你会得到一个 ObjectDisposedException。让容器处理处置。

这实际上是与 IDisposable classes 的常见混淆。如果您的 class 本身拥有依赖项,您应该只实施 IDisposable。如果它的所有依赖项都是 注入的 ,你不应该实现 IDisposable,因为它不拥有任何需要处理的东西。同样,你不应该处理任何注入到你的 class 中的东西,因为它不拥有这些依赖项。只处理你特别新的东西。如果您没有看到关键字 new,您可能不应该处理。

不需要调用 Dispose 方法,但如果出于某些原因需要,您仍然可以调用它。

证明:HttpClient and lifetime management

Disposal of the client isn't required. Disposal cancels outgoing requests and guarantees the given HttpClient instance can't be used after calling Dispose. IHttpClientFactory tracks and disposes resources used by HttpClient instances. The HttpClient instances can generally be treated as .NET objects not requiring disposal.

勾选 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 的调用什么都不做。但这并不危险。