关于.net核心:应该丢弃由HttpClientFactory创建的HttpClient实例吗?

Should HttpClient instances created by HttpClientFactory be disposed?

因此,我已经在Startup.cs中的服务集合中注册了一个命名客户端:

1
2
services.AddHttpClient(someServiceName,
                       client => client.BaseAddress = baseAddress);

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

使用此IHttpClientFactory,我可以想到一个客户端实例:

1
var client = httpClientFactory.CreateClient(someServiceName)

曾几何时,必须非常谨慎地处理HttpClient实例,因为这很少是正确的事情。

但是,现在我们有了HttpClientFactory,这不再重要了吗? 应该/可以不用担心处置此client吗? 例如

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


不。您不应该处置您的客户。更笼统地说,您不应处理通过DI容器检索到的任何内容,DI容器在ASP.NET Core中默认为服务集合。生命周期由DI容器管理,因此,如果您处置客户端,但稍后将其注入某些对象,则会得到ObjectDisposedException。让容器处理。

这实际上是与IDisposable类的常见混淆。如果您的类本身拥有依赖项,则您个人应该只实现IDisposable。如果注入了所有依赖项,则不应实现IDisposable,因为它不拥有任何需要处理的内容。同样,您不应处理注入类中的任何内容,因为它不拥有那些依赖关系。只处理您专门处理的新事物。如果您没有看到关键字new,则可能不应该进行处理。


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

证明:HttpClient和生命周期管理

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.

检查DefaultHttpClientFactory的来源:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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的调用没有任何作用。但这并不危险。