如何使用 HttpClient 处理数据提供者实例?

How to dispose the data provider instance using HttpClient?

我已经使用存储库模式创建了我的数据提供者。

首先,我设计了一个基础仓库界面如下:

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 网络应用程序,并在 class 级别定义了存储库:

IOrderRepository _orderRepository = new OrderRepository();

当我在我的 CRUD 操作中调用 _orderRepository 时,它在使用后没有命中处置。为了解决这个问题,我最终像这样实施:

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

这会影响 Dispose 但它是反模式的。

我在实现中遗漏了什么,即每次调用时都没有处理实例?

在您的通用存储库中编写 Dispose 方法并不意味着它会在您需要时自动调用。它旨在单独调用,因此您 必须 要么使用 using 语句(如您所示),要么在代码中使用 Dispose 方法。

或者,您可以将该工作留给垃圾收集器。

如果您确信要使用 GC.SuppressFinalize(this);

,您还应该在通用存储库中创建终结器

在此处阅读更多相关信息 - When should I use GC.SuppressFinalize()?

正如 R Jain 所指出的,您还应该创建一个静态 class 来保存您的 HttpClient。您必须根据需要使用 HttpResponseMessages 或 HttpContent。

阅读更多资源:

  1. https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/

您不应该在每次请求后都处理 HTTPClient。

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

如上link所说——

Therefore, HttpClient is intended to be instantiated once and reused throughout the life of an application. Instantiating an HttpClient class for every request will exhaust the number of sockets available under heavy loads. That issue will result in SocketException errors. Possible approaches to solve that problem are based on the creation of the HttpClient object as singleton or static, as explained in this Microsoft article on HttpClient usage.