I have created my data provider using Repository Pattern.
First, I designed a base repository interface as following:
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);
}
Then I implemented it:
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;
}
}
Then I created custom repository interface for each of my entities. For example:
internal interface IOrderRepository : IGenericRepository<Order, int>
{
Task<IEnumerable<Order>> GetOrderBySomeConditionAsync(string condition );
}
And finally, I implemented the custom repository:
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
}
}
Note that HttpClientHelper
uses HttpClient
and needs to be disposed manually.
I have created a MVC web application and have defined the repositories at the class level as such:
IOrderRepository _orderRepository = new OrderRepository();
When I call _orderRepository
in my CRUD operations, it does not hit dispose after its use. In order to fix that I have ended up implementing like this:
private async Task<IEnumerable<OrderViewModel>> GetOrders()
{
using(var orderRepository = new OrderRepository())
return await orderRepository.GetManyAsync();
}
This would hit the Dispose but is anti pattern.
What am I missing in my implementation that the instance is not disposed on each call?
You should not be disposing HTTPClient after every request.
As the above link says -
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.