Должен ли я кэшировать и повторно использовать HttpClient, созданный из HttpClientFactory? - PullRequest
0 голосов
/ 08 февраля 2019

Мы можем прочитать здесь ВЫ ИСПОЛЬЗУЕТЕ НЕПРАВИЛЬНО HTTPCLIENT И УДАЛЯЕТЕ ВАШЕ ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ , что мы не должны создавать и использовать HttpClient для каждого http-запроса.Вместо этого его следует кэшировать и использовать повторно (например, как Singleton в контейнере DI).Кроме того, в официальной документации .NET для HttpClient :

HttpClient предназначен для однократного создания и повторного использования в течение всего жизненного цикла приложения.Создание класса HttpClient для каждого запроса приведет к исчерпанию количества сокетов, доступных при больших нагрузках.Это приведет к ошибкам SocketException.Ниже приведен пример правильного использования HttpClient.

Рекомендуется использовать HttpClientFactory, но после просмотра:

  public interface IHttpClientFactory
  {
    /// <summary>
    /// Creates and configures an <see cref="T:System.Net.Http.HttpClient" /> instance using the configuration that corresponds
    /// to the logical name specified by <paramref name="name" />.
    /// </summary>
    /// <param name="name">The logical name of the client to create.</param>
    /// <returns>A new <see cref="T:System.Net.Http.HttpClient" /> instance.</returns>
    /// <remarks>
    /// <para>
    /// Each call to <see cref="M:System.Net.Http.IHttpClientFactory.CreateClient(System.String)" /> is guaranteed to return a new <see cref="T:System.Net.Http.HttpClient" />
    /// instance. Callers may cache the returned <see cref="T:System.Net.Http.HttpClient" /> instance indefinitely or surround
    /// its use in a <langword>using</langword> block to dispose it when desired.
    /// </para>
    /// <para>
    /// The default <see cref="T:System.Net.Http.IHttpClientFactory" /> implementation may cache the underlying
    /// <see cref="T:System.Net.Http.HttpMessageHandler" /> instances to improve performance.
    /// </para>
    /// <para>
    /// Callers are also free to mutate the returned <see cref="T:System.Net.Http.HttpClient" /> instance's public properties
    /// as desired.
    /// </para>
    /// </remarks>
    HttpClient CreateClient(string name);
  }

говорится, что каждый вызов всегда создаетЭкземпляр HttpClient и вызывающая сторона могут его кэшировать.

Каждый вызов IHttpClientFactory.CreateClient гарантированно возвращает новый экземпляр HttpClient.Вызывающие абоненты могут кэшировать возвращенный экземпляр на неопределенный срок или окружить его использование в блоке using, чтобы утилизировать его при желании.

Поэтому вопрос заключается в том, должен ли я полностью положиться на HttpClientFactory или Iдолжен ли кеш все же создавать HttpClient из него?

В нашем проекте мы используем HttpClientFactory.CreateClient каждый раз, когда мы делаем запрос, и у него все еще будут исключения сокетов.

Ответы [ 2 ]

0 голосов
/ 08 февраля 2019

В релизе ASP.NET Core 2.2 все хорошо изменилось.Ожидается, что HttpClient будет потребляться только через DI, который внутренне обрабатывает все необходимое для вас кэширование, используя HttpClientFactory.Следующая статья документации была обновлена, чтобы отразить эти новые варианты использования: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/http-requests?view=aspnetcore-2.2

Кроме того, @RyanNowak из группы ASP.NET Core рассмотрел все эти изменения в следующем сеансе ASP.Net Core Community Standup:https://www.youtube.com/watch?v=Lb12ZtlyMPg Если вы еще не смотрели его, я настоятельно рекомендую посмотреть его, так как это очень информативно и познавательно.

Вот небольшой пример, демонстрирующий использование.В вызове метода Startup.ConfigureServices:

services.AddHttpClient();

Примечание : существует несколько шаблонов использования, это самый базовый.Посмотрите документы для других шаблонов, которые могут лучше соответствовать вашим потребностям.

Позже, в классе, откуда вы хотели бы делать http-запросы, возьмите зависимость от IHttpClientFactory и позвольте DI создать его экземплярдля вас по мере необходимости.Вот пример из Microsoft Docs:

public class BasicUsageModel : PageModel
{
    private readonly IHttpClientFactory _clientFactory;

    public IEnumerable<GitHubBranch> Branches { get; private set; }

    public bool GetBranchesError { get; private set; }

    public BasicUsageModel(IHttpClientFactory clientFactory)
    {
        _clientFactory = clientFactory;
    }

    public async Task OnGet()
    {
        var request = new HttpRequestMessage(HttpMethod.Get, 
            "https://api.github.com/repos/aspnet/docs/branches");
        request.Headers.Add("Accept", "application/vnd.github.v3+json");
        request.Headers.Add("User-Agent", "HttpClientFactory-Sample");

        var client = _clientFactory.CreateClient();

        var response = await client.SendAsync(request);

        if (response.IsSuccessStatusCode)
        {
            Branches = await response.Content
                .ReadAsAsync<IEnumerable<GitHubBranch>>();
        }
        else
        {
            GetBranchesError = true;
            Branches = Array.Empty<GitHubBranch>();
        }                               
    }
}
0 голосов
/ 08 февраля 2019

HttpClient только IDisposable, потому что HttpMessageHandler равно IDisposable.В действительности, это HttpMessageHandler, который должен быть долгоживущим.

HttpClientFactory работает, сохраняя долгоживущий HttpMessageHandler внутри.Всякий раз, когда вы запрашиваете HttpClient, он использует долгоживущий HttpMessageHander и говорит HttpClient , а не утилизировать его, когда утилизируется HttpClient.

Выможно увидеть, что на GitHub :

public HttpClient CreateClient(string name)
{
    // ...

    // Get a cached HttpMessageHandler
    var handler = CreateHandler(name);

    // Give it to a new HttpClient, and tell it not to dispose it
    var client = new HttpClient(handler, disposeHandler: false);

    // ...

    return client;
}

Таким образом, технически не имеет значения, кэшируете ли вы HttpClient или удаляете его сразу - удаление ничего не делает (потому что было сказано не распоряжаться HttpClientHandler, как это управляется HttpClientFactory).

Относительно утилизации HttpClient, MSDN говорит :

Утилизация клиента не требуется.Утилизация отменяет исходящие запросы и гарантирует, что данный экземпляр HttpClient не может быть использован после вызова Dispose.IHttpClientFactory отслеживает и удаляет ресурсы, используемые экземплярами HttpClient.Экземпляры HttpClient, как правило, могут рассматриваться как объекты .NET, не требующие удаления.

Сохранение одного экземпляра HttpClient в течение долгого времени является распространенным шаблоном, используемым до создания IHttpClientFactory.Этот шаблон становится ненужным после перехода на IHttpClientFactory.

Я подозреваю, что SocketException s, которые вы видите, имеют другую причину.Может быть, задать новый вопрос, ориентированный на них?

...