Wire-up nested Interfaces

Oct 30, 2013 at 11:10 PM
Hi, I'm looking for the right register method here:

I have a Generic Repository:
    public class ReadRepository<TEntity> 
        : IReadRepository<TEntity> where TEntity : class
        public ReadRepository(ClientManagementContext context)
            Context = context;
And it's Interface:
public interface IReadRepository<TEntity> where TEntity : class
The Generic has virtual methods like:
public virtual TEntity GetById(object id)
I'd like to Extend (not using Extensions at the moment), this Generic Repo with a more specialized one (turning it from a strictly CRUD type Repo into an Agg Root type, so to speak). I'm only going to be doing this for simple type add on methods.

So I create a new Interface that inherits from the base Generic Repo interface:
    public interface ITenantReadRepository : IReadRepository<Tenant>
        IEnumerable<ContactType> GetAllContactTypes();
In the above interface I resolve the generic type.

Now I inherit from the Generic Repo (again, that's also implementing IReadRepository<T>)
    public class TenantReadRepository
        : ReadRepository<Tenant>
        , ITenantReadRepository
        public TenantReadRepository(ClientManagementContext context) 
            : base(context) { }

        public IEnumerable<ContactType> GetAllContactTypes()
So to sum up, I'm sub-classing from the Generic ReadRepository<T> that implements IReadRepository<T>, but in this sub-class I'm also implementing ITenantReadRepository<Tenant>, which happeneds to also derive from IReadRepository<T> (but is resolved).

This is what my bootstrap method looks like so far:


            container.RegisterDecorator(typeof(IReadRepository<>), typeof(LoggingReadRepository<>));
            container.RegisterDecorator(typeof(IWriteRepository<>), typeof(LoggingWriteRepository<>));
How do I wire this up?

Thanks for all your help!
Oct 31, 2013 at 6:28 PM
This seems to work: container.Register(typeof (ITenantReadRepository), typeof (TenantReadRepository));

Oct 31, 2013 at 7:44 PM
Please note that your registered LoggingReadRepository<T> and LoggingWriteRepository<T> decorators will not be applied to TenantReadRepository, simply because when you resolve IITenantReadRepository, the container must return an IITenantReadRepository and your decorators don't implement that interface. You'll have to create a decorator for each specific interface and that's why I consider it an anti-pattern to have specific interfaces (such as IITenantReadRepository) that derive from such geneneric base interface (such as IReadRepository<T>). I've ranted about this here.
Nov 1, 2013 at 1:54 AM
Edited Nov 1, 2013 at 2:12 AM
Well how should I added small-incremental functionality to the Generic Repository without direct access to the context? For example, if I use Extensions, I don't have access to the Repository's DbContext unless I make it Public (which is wrong), and if I sub-class the base Generic Repository, I need to do what I did above (which is to make a new interface that includes the new methods).

What it seems like you are suggesting by linking to your (amazing insightful) blog post (that you in fact wrote) is that for simple additions to the Generic Repository, for example GetContactTypes() (where contact types directly relates to the Tenant table in the ORM), I should turn to the Command Query Separation pattern. Which by the way I don't take issue with and had planned to use when things got more complicated, but for this simple addition, what is the alternative?

Nov 1, 2013 at 8:34 AM
> Well how should I added small-incremental functionality to the Generic Repository

You shouldn't. That would break the Open/Closed Principle. As you can read in this article I advice to prevent implementing custom query methods on repositories, since that breaks three out of five SOLID principles (namely the SRP, OCP and ISP) which causes problems in the maintainability of your application. Instead, each custom query should get its own class in the system.

> but for this simple addition, what is the alternative?

For me, there is no alternative. Even truly CRUD applications can benefit greatly from using this query/handler pattern, since even the simplest CRUD systems need custom queries and they can even get quite complex in CRUD applications.
Marked as answer by dot_NET_Junkie on 2/26/2014 at 1:23 PM
Nov 4, 2013 at 4:28 PM
Edited Nov 4, 2013 at 4:29 PM
What about this approach to the Repository pattern?
Nov 4, 2013 at 5:46 PM
That approach still uses the same generic repository, without implementing queries on specific implementations. But do note that those repositories implement IQueryable which makes it hard to unit test code that uses that abstraction.