Следует ли удалять экземпляры HttpClient, созданные HttpClientFactory?

Итак, я зарегистрировал именованного клиента с коллекцией сервисов в моем 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>();
    //...
}

person spender    schedule 18.06.2018    source источник
comment
Ознакомьтесь с этой статьей, в которой объясняется, как клиент обрабатывается на заводе https://www.stevejgordon.co.uk/introduction-to-httpclientfactory-aspnetcore   -  person Nkosi    schedule 18.06.2018
comment
@Nkosi Да, я это читал. Однако я обнаружил код, который очень похож на последний фрагмент моего вопроса, и мне интересно, нужно ли мне его исправить.   -  person spender    schedule 18.06.2018


Ответы (2)


Вызов метода Dispose не требуется, но вы все равно можете вызвать его, если вам это нужно по каким-либо причинам.

Доказательство: HttpClient и управление временем жизни

Ликвидация клиента не требуется. Disposal отменяет исходящие запросы и гарантирует, что данный экземпляр HttpClient нельзя использовать после вызова Dispose. 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).

Итак, вызов HttpClient.Dispose ничего не делает. Но это не опасно.

person Mark Shevchenko    schedule 23.01.2019

Нет. Вы не должны избавляться от своего клиента. Чтобы быть более общим, вы не должны избавляться от чего-либо, полученного через контейнер DI, который в ASP.NET Core по умолчанию является коллекцией служб. Время жизни управляется контейнером DI, поэтому, если вы избавляетесь от клиента, но позже он во что-то внедряется, вы получите ObjectDisposedException. Дайте контейнеру утилизировать.

На самом деле это обычная путаница с IDisposable классами. Лично вам следует реализовывать IDisposable только в том случае, если сам ваш класс владеет зависимостями. Если все его зависимости внедрены, вам не следует реализовывать IDisposable, поскольку он не владеет ничем, что требует удаления. Точно так же вы не должны избавляться от чего-либо, внедренного в ваш класс, поскольку он не владеет этими зависимостями. Выбрасывайте только то, что вы специально обновили. Если вы не видите ключевое слово new, вероятно, вам не следует выбрасывать.

person Chris Pratt    schedule 18.06.2018
comment
Это немного сбивает с толку, потому что клиент не извлекается через контейнер DI. factory извлекается через контейнер DI. - person Kieren Johnstone; 15.04.2019
comment
И фабрика владеет клиентами и распоряжается ими. Когда завод будет ликвидирован, он избавится от всех своих клиентов. По-прежнему действует то же правило: если вы явно не обновляете его, не удаляйте его. - person Chris Pratt; 15.04.2019
comment
но имя в httpClientFactory.CreateClient (someServiceName), похоже, подразумевает, что вы его обновили, так что это сбивает с толку. Я с @KierenJohnstone - person Wiebe Tijsma; 16.07.2019
comment
Не имеет значения, что ресурс обновлен, важно только то, контролируете ли вы его время жизни или нет. В случае с фабрикой, фабрика создает экземпляр и контролирует время жизни, а не вы. В этом-то и дело. Выбрасывайте только те ресурсы, которые принадлежат вам. - person Chris Pratt; 16.07.2019
comment
@ChrisPratt Согласитесь, что это было бы меньше проблем, если бы C # или .NET включали какую-то семантику для времени жизни объекта и владения, чтобы предотвратить подобную путаницу? Даже что-то простое, например интерфейс (например, IDisposableHahahNotReally) или обращение к объектам с помощью объекта типа интеллектуального указателя, например OwnedObject<T>.Instance и BorrowedObject<T>.Value). - person Dai; 23.08.2019
comment
Не совсем. На самом деле это очень просто. Если вы не используете new, вы не избавляетесь от него. Вызов метода создания фабрики - это не одно и то же. Там фабрика обновляет вещи, поэтому за утилизацию отвечает она, а не вы. И, конечно, если вы делаете инъекции, вы явно не избавляетесь от этого. - person Chris Pratt; 23.08.2019
comment
@ChrisPratt Я не думаю, что это важно. Я помню, как читал в выпуске GitHub в репозитории ASP.NET, что HttpClientHandler нельзя удалять. Когда вы удаляете HttpClient (созданный фабрикой, как указано выше), обработчик сообщает клиентам, чтобы они не избавлялись от него, когда он будет удален. Таким образом, такой код не вызывает проблем using (var client = _httpClientFactory.CreateClient()). (Думаю) :) - person onefootswill; 25.09.2019
comment
Возможно нет. Я знаю, что HttpMessageHandler - это то, что на самом деле удерживает фабрика, а экземпляры HttpClient имеют временную область действия. Однако остается простой факт: вы не должны избавляться от того, что вы не создаете и не владеете. Если бы реализация изменилась, вы могли бы внезапно что-нибудь сломать. - person Chris Pratt; 25.09.2019