4

Currently, my code is similar to this (shortened just to make a point):

DAL

Repository Interface

public interface IRepository<TEntity, in TKey>
{
    IList<TEntity> GetAll();
    TEntity Get(TKey id);
    TEntity Add(TEntity item);
    TEntity Update(TEntity item);
    bool Remove(TKey id);
}

Base EF repository

public class BaseEFRepository<TEntity, TKey> : IRepository<TEntity, TKey> where TEntity: class, IEntity<TKey> where TKey: struct
{
    protected readonly DbContext _dbContext;

    public BaseRepository()
    {
        _dbContext = new MyDB();
        _dbContext.Configuration.ProxyCreationEnabled = false;
        _dbContext.Configuration.LazyLoadingEnabled = false;
    }

    public virtual TEntity Get(TKey id)
    {
        return _dbContext.Set<TEntity>().Find(id);
    }

    public virtual IList<TEntity> GetAll()
    {
        return _dbContext.Set<TEntity>()
            .ToList();
    }

    public virtual TEntity Add(TEntity item)
    {
        _dbContext.Set<TEntity>().Add(item);
        _dbContext.SaveChanges();
        return item;
    }
    .....
    .....
}

A sample implementation of the base repository

public interface IContactsRepository : IRepository<Contact, long>
{
    Contact GetByEmployeeId(string empId, ContactType type);
    IList<Contact> GetByEmployeeId(string empId);
}

public class ContactsRepository : BaseEFRepository<Contact, long>, IContactsRepository
{
    public Contact GetByEmployeeId(string empId, ContactType type)
    {
        var contact = _dbContext.Set<Contact>()
            .FirstOrDefault(d => d.EmployeeId == empId && d.ContactType == type);

        return contact;
    }

    public IList<Contact> GetByEmployeeId(string empId)
    {
        var contacts = _dbContext.Set<Contact>()
            .Where(d => d.EmployeeId == empId)
            .ToList();

        return contacts;
    }
}

BLL

public class Contacts
{
    public Contact Get(long id)
    {
        IContactsRepository repo = ResolveRepository<IContactsRepository>();
        var contact = repo.Get(id);
        return contact;
    }

    public Contact GetByEmployeeId(string empId, ContactType type)
    {
        IContactsRepository repo = ResolveRepository<IContactsRepository>();         
        return repo.GetByEmployeeId(empId, type);
    }
    .......
    .......
}

Now, everything is fine. I can simply do something like this:

 var _contacts = new Contacts();
 var contact = _contacts.GetByEmployeeId("C1112", ContactType.Emergency);

The confusion started when I read this blog post, the author says that using code like:

IContactsRepository repo = ResolveRepository<IContactsRepository>();  

is a bad technique and it's anti-pattern and one should inject everything at the root of code. I can't see how would I do this with repository pattern. I am consuming this using a WCF. So, how on earth would I inject everything from the first call in WCF? I can't get it. What am I missing here?

One last thing, in this case the WCF is the last layer, and it should be only aware of the layer before it, which is the BLL layer. If I am going to implement anything as the author of that blog suggested, I will make the WCF layer aware of the DAL layer, isn't that bad practice? correct me if I am wrong.

Nean Der Thal
  • 2,653
  • 3
  • 17
  • 33
  • So, your application is a WCF application? Is it hosted in IIS or is it self hosted? In a console application? Or in a windows service? – Yacoub Massad Jan 20 '16 at 11:50

3 Answers3

3

You need to use Constructor Injection and then compose your objects in the Composition Root.

When you use Constructor Injection, you inject the dependencies through the constructors, so your classes would look like something like this:

public class BaseRepository
{
    protected readonly DbContext _dbContext;

    //...
    public BaseRepository(DbContext context)
    {
        _dbContext = context;
    }
    //...
}

public class ContactsRepository : BaseEFRepository<Contact, long>, IContactsRepository
{
    //...
    public ContactsRepository(DbContext context)
        :base(context)
    {

    }
    //...
}

public class Contacts
{
    private readonly IContactsRepository m_ContactsRepository;

    public Contacts(IContactsRepository contacts_repository)
    {
        m_ContactsRepository = contacts_repository;
    }

    public Contact Get(long id)
    {
        var contact = m_ContactsRepository.Get(id);
        return contact;
    }
    //...
}

Then in the Composition Root your would compose all your objects together. Optionally via a DI container.

Here is an example of such composition that uses Pure DI:

var context = new MyDB();

context.Configuration.ProxyCreationEnabled = false;

context.Configuration.LazyLoadingEnabled = false;

var contacts = new Contacts(new ContactsRepository(context));

In a WCF application that is hosted in IIS, the Composition Root is a custom ServiceHostFactory. This answer provides more details about how to do that.

Community
  • 1
  • 1
Yacoub Massad
  • 26,006
  • 2
  • 31
  • 56
  • Excuse my ignorance, but won't this make the WCF layer aware of the DAL layer, while it should only be aware of the BLL layer... Correct me if I am wrong. – Nean Der Thal Jan 20 '16 at 14:21
  • The WCF hosting code has to be aware of everything, yes. It is the Composition Root. However, the service layer (e.g. the `Contacts` class) does not need to know about everything. – Yacoub Massad Jan 20 '16 at 14:24
  • You should consider the WCF hosting logic a separate part of the system and call it the "Composition Root". This is totally different than the service layer that contains the WCF services themselves. – Yacoub Massad Jan 20 '16 at 14:26
  • Yacoub, ok, now it starts to make sense. I will dig deep into this. Not being a programmer (me) and trying to program correctly is a pain in the ass.. I should change my hobby :/ – Nean Der Thal Jan 20 '16 at 14:27
2

You need to identify a seam suitable for use as a composition root.

For WCF, you need to get creative - you must create a custom ServiceHostFactory to intercept the correct place to compose your object root.

See for example this article and this article from Mark Seemann (author of "Dependency Injection in .Net" - a book I think you would find very useful).

Many free DI containers, such as Autofac, provide off-the-shelf support for WCF, which is probably the best approach.

I really can't recommend Seemann's book highly enough - it goes into a lot of detail about this.

You might also find this article on using Autofac DI with ASP.Net and a repository interesting.

Matthew Watson
  • 90,570
  • 7
  • 128
  • 228
  • Excuse my ignorance, but won't this make the WCF layer aware of the DAL layer, while it should only be aware of the BLL layer... Correct me if I am wrong. – Nean Der Thal Jan 20 '16 at 14:23
  • @HeidelBerGensis The WCF layer is a seam used as a composition root, where some code that is aware of multiple layers resides. This is OK because it is just where a DI container is wired up. – Matthew Watson Jan 20 '16 at 15:14
2

@Matthew's post should answer your question. However, I would like to mention one thing I noticed in your code in relation to the question. You should not try to manually resolve the dependency but it should be injected by the container. I have modified your code to show this behaviour:

public class Contacts
{
    private IContactsRepository repo;
    public Contacts(IContactsRepository injectedContactsRepository)
    {
        repo = injectedContactsRepository;
    }


    public Contact Get(long id)
    {
        var contact = repo.Get(id);
        return contact;
    }

//and other methods definitions...
}
Martin
  • 594
  • 4
  • 10