56

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

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

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

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

var client = httpClientFactory.CreateClient(someServiceName)

曾几何时,在处理HttpClient实例时必须非常小心,因为这很少是正确的做法

但是,现在我们有了HttpClientFactory,这还重要吗?应该/可以client放心地处理吗?例如

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

2 回答 2

41

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

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

于 2018-06-18T14:56:19.827 回答
30

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

证明:HttpClient 和生命周期管理

不需要处理客户端。Disposal 取消传出请求并保证在调用 Dispose 后不能使用给定的 HttpClient 实例。IHttpClientFactory 跟踪和释放 HttpClient 实例使用的资源。HttpClient 实例通常可以被视为不需要处置的 .NET 对象。

检查来源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)。

所以,调用 theHttpClient.Dispose什么都不做。但这并不危险。

于 2019-01-23T11:38:55.770 回答