2

This article explains how to create a generic HttpClient class with all the basic CRUD operations. Then it creates a type specific repository for a specific POCO object (Called Member).

What I fail to understand is the need for the MemberReposity class that is returning exactly what the GenericHttpClient class would return for a specific type? Can't I simply rename the GenericHttpClient to GenericReposity and then use this for all of my POCO objects CRUD operations? In another word, why would I need a unique repository for every object if they all only require basic CRUD operations?

I could simply instantiate them on my form like this:

private GenericReposity<Customer, int> _customerClient = new GenericReposity<Customer, string>(url, "api/Customers/");

and then get a customer this way:

_customerClient.GetAsync(5);

Am I missing a point here?


UPDATE

After reading about Anti-Pattern 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
}

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
    }
}

This way I can get all the simple CRUD operations without having to implement them one by one for each entity as well as any custom ones. Is this a proper approach? Or is this considered anti-pattern?

amindomeniko
  • 417
  • 6
  • 23
  • 1
    Generic repository is considered an anti-pattern. See if [this](https://stackoverflow.com/a/51781877/5779732) helps you. – Amit Joshi Oct 15 '18 at 10:31
  • @AmitJoshi after reading your response in the other post and a few other articles, I updated my post. Can you tell me if this is considered a correct approach in your opinion please? – amindomeniko Oct 18 '18 at 16:00

2 Answers2

1

Some day you might want to add things that would be unique per entity type like data validation, or encrypting personal information when the data is at rest.

Leo Bartkus
  • 1,925
  • 13
  • 17
1

Your new approach (after update) looks great.

With this, you bypass all the drawbacks of generic repository; still taking advantage of code reuse from base generic repository.

Not big deal but consider making all methods in base repository protected so that those should be only accessible in concrete repository. Of-course this suggestion can be neglected if all concrete repositories implement that method.

Amit Joshi
  • 15,448
  • 21
  • 77
  • 141