Как избавиться от экземпляра поставщика данных с помощью HttpClient? - PullRequest
0 голосов
/ 20 сентября 2019

Я создал свой поставщик данных, используя Шаблон репозитория.

Сначала я спроектировал базовый интерфейс репозитория следующим образом:

internal interface IGenericRepository<T, in TResourceIdentifier>
{
    Task<IEnumerable<T>> GetManyAsync();
    Task<T> GetAsync(TResourceIdentifier id);
    Task PutAsync(T model);
    Task<T> PostAsync(T model);
    Task DeleteAsync(TResourceIdentifier id);
}

Затем я реализовал его:

public class GenericRepository<T, TResourceIdentifier> : IDisposable, IGenericRepository<T, TResourceIdentifier> 
    where T : class
{
    private bool _disposed;
    protected HttpClientHelper<T, TResourceIdentifier> Client;

    protected GenericRepository(string addressSuffix)
    {
        Client = new HttpClientHelper<T, TResourceIdentifier>(Properties.Settings.Url, addressSuffix);
    }

    public async Task<IEnumerable<T>> GetManyAsync()
    {
        return await Client.GetManyAsync();
    }

    // All other CRUD methods and dispose

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    private void Dispose(bool disposing)
    {
        if(_disposed || !disposing) return;

        if(Client != null)
        {
            var mc = Client;
            Client = null;
            mc.Dispose();
        }

        _disposed = true;
    }
}

Затем я создал собственный интерфейс репозитория для каждого из моихюридические лица.Например:

internal interface IOrderRepository : IGenericRepository<Order, int>
{
    Task<IEnumerable<Order>> GetOrderBySomeConditionAsync(string condition );

}

И наконец, я реализовал пользовательский репозиторий:

public class OrderRepository : GenericRepository<Order, int>, IOrderRepository
{
    public OrderRepository(string addressSuffix) : base(addressSuffix)
    {
    }

    public async Task<IEnumerable<Order>> GetOrderBySomeConditionAsync(string condition)
    {
        //get all the orders (GetManyAsync()) and then returns the ones meeting the condition
    }
}

Обратите внимание, что HttpClientHelper использует HttpClient и должен быть удален вручную.

Я создал веб-приложение MVC и определил хранилища на уровне класса следующим образом:

IOrderRepository _orderRepository = new OrderRepository();

Когда я вызываю _orderRepository в моих операциях CRUD, оно не удаляет утилиту утилизации.после его использования.Чтобы исправить это, я реализовал так:

private async Task<IEnumerable<OrderViewModel>> GetOrders()
{
    using(var orderRepository = new OrderRepository())
         return await orderRepository.GetManyAsync();
}

Это ударило бы по Dispose, но это анти-паттерн.

Что мне не хватает в моей реализации, чтобы экземпляр не располагался при каждом вызове?

Ответы [ 2 ]

3 голосов
/ 20 сентября 2019

Вы не должны утилизировать HTTPClient после каждого запроса.

[https://docs.microsoft.com/en-us/dotnet/architecture/microservices/implement-resilient-applications/use-httpclientfactory-to-implement-resilient-http-requests][1]

Как видно из приведенной выше ссылки -

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

1 голос
/ 20 сентября 2019

Запись метода Dispose в вашем универсальном репозитории не означает, что он будет вызываться автоматически, когда вы захотите.Он предназначен для отдельного вызова, поэтому вы должны либо использовать оператор using (как вы показали), либо метод Dispose внутри вашего кода.

В качестве альтернативы выможете оставить эту работу для сборщика мусора.

Вы также должны создать финализатор в своем универсальном репозитории, если вы уверены в использовании GC.SuppressFinalize(this);

Подробнее об этом здесь - Когда я должен использовать GC.SuppressFinalize ()?

Как указывалось R Jain , вы также должны создать статический класс для хранения вашего HttpClient.Вы должны будете использовать HttpResponseMessages для своих нужд или HttpContent.

Еще несколько ресурсов для чтения:

  1. Один экземпляр HttpClient с разными заголовками аутентификации
  2. https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/
...