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>();
//...
} |
-
检查本文,该文章解释了工厂如何处理客户端stevejgordon.co.uk/introduction-to-httpclientfactory-aspnetc矿石
-
@Nkosi是的,我读过。 但是,我找到了一些看起来很像我问题中最后一个片段的代码,我想知道是否需要修复它。
不。您不应该处置您的客户。更笼统地说,您不应处理通过DI容器检索到的任何内容,DI容器在ASP.NET Core中默认为服务集合。生命周期由DI容器管理,因此,如果您处置客户端,但稍后将其注入某些对象,则会得到ObjectDisposedException。让容器处理。
这实际上是与IDisposable类的常见混淆。如果您的类本身拥有依赖项,则您个人应该只实现IDisposable。如果注入了所有依赖项,则不应实现IDisposable,因为它不拥有任何需要处理的内容。同样,您不应处理注入类中的任何内容,因为它不拥有那些依赖关系。只处理您专门处理的新事物。如果您没有看到关键字new,则可能不应该进行处理。
-
嗯,这有点令人困惑,因为客户端不是通过DI容器检索的。通过DI容器检索工厂。
-
工厂拥有并处置客户。处置工厂时,它将处置其拥有的任何客户。同样的规则仍然适用:如果您不明确地对其进行更新,请不要对其进行处置。
-
但是httpClientFactory.CreateClient(someServiceName)中的命名似乎暗示您对其进行了更新,因此这是令人困惑的部分。我与@KierenJohnstone
-
更新资源无关紧要,仅取决于您是否控制其寿命。对于工厂,工厂进行实例化,并且它控制生命周期,而不是您。这才是重点。仅处置属于您的资源。
-
@ChrisPratt您是否同意,如果C#或.NET为对象生存期和所有权包含某种语义以防止这种混淆,那么这将不是一个大问题?甚至是简单的东西,例如界面(例如IDisposableHahahNotReally)或通过智能指针类型的对象引用对象,例如OwnedObject< T >.Instance和BorrowedObject< T >.Value)。
-
并不是的。实际上,它非常简单。除非您使用new,否则请勿丢弃。调用工厂的create方法是不一样的。那里,工厂正在更新东西,所以它负责处理,而不是您。而且,当然,如果您要注射,显然您不会处理。
-
@ChrisPratt我不认为这很重要。我记得在ASP.NET回购上的GitHub问题中读到,它是HttpClientHandler,不能丢弃。当您处理HttpClient(由上面的工厂创建)时,处理程序会"告诉"客户端不要处理它。因此,这样的代码根本没有问题。 (我认为) :)
-
也许不是。我知道HttpMessageHandler是工厂实际持有的东西,并且HttpClient实例是临时作用域的。但是,简单的事实仍然是您不应该处置不创建或不拥有的东西。如果要更改实现,则可能会突然中断某些操作。
不需要调用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的调用没有任何作用。但这并不危险。