DI和存储库模式

目前,我的代码与此类似(缩短只是为了说明一点):

DAL

存储库接口

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

基本EF存储库

 public class BaseEFRepository : IRepository where TEntity: class, IEntity 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().Find(id); } public virtual IList GetAll() { return _dbContext.Set() .ToList(); } public virtual TEntity Add(TEntity item) { _dbContext.Set().Add(item); _dbContext.SaveChanges(); return item; } ..... ..... } 

基本存储库的示例实现

 public interface IContactsRepository : IRepository { Contact GetByEmployeeId(string empId, ContactType type); IList GetByEmployeeId(string empId); } public class ContactsRepository : BaseEFRepository, IContactsRepository { public Contact GetByEmployeeId(string empId, ContactType type) { var contact = _dbContext.Set() .FirstOrDefault(d => d.EmployeeId == empId && d.ContactType == type); return contact; } public IList GetByEmployeeId(string empId) { var contacts = _dbContext.Set() .Where(d => d.EmployeeId == empId) .ToList(); return contacts; } } 

BLL

 public class Contacts { public Contact Get(long id) { IContactsRepository repo = ResolveRepository(); var contact = repo.Get(id); return contact; } public Contact GetByEmployeeId(string empId, ContactType type) { IContactsRepository repo = ResolveRepository(); return repo.GetByEmployeeId(empId, type); } ....... ....... } 

现在,一切都很好。 我可以简单地做这样的事情:

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

当我阅读这篇博文时,混乱开始,作者说使用如下代码:

 IContactsRepository repo = ResolveRepository(); 

是一种糟糕的技术,它是反模式的,应该在代码的根源注入所有内容。 我无法看到如何使用存储库模式执行此操作。 我正在使用WCF消费它。 那么,从WCF的第一次调用开始,我将如何注入所有内容? 我无法得到它。 我在这里想念的是什么?

最后一点,在这种情况下,WCF是最后一层,它应该只知道它之前的层,即BLL层。 如果我要按照该博客的作者建议实现任何内容,我将使WCF层知道DAL层,这不是那么糟糕的做法吗? 如果我错了,请纠正我。

您需要使用构造函数注入,然后在组合根中组合您的对象。

当您使用构造函数注入时,您通过构造函数注入依赖项,因此您的类看起来像这样:

 public class BaseRepository { protected readonly DbContext _dbContext; //... public BaseRepository(DbContext context) { _dbContext = context; } //... } public class ContactsRepository : BaseEFRepository, 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; } //... } 

然后在Composition Root中,您将把所有对象组合在一起。 可选择通过DI容器。

以下是使用Pure DI的此类组合物的示例:

 var context = new MyDB(); context.Configuration.ProxyCreationEnabled = false; context.Configuration.LazyLoadingEnabled = false; var contacts = new Contacts(new ContactsRepository(context)); 

在IIS中承载的WCF应用程序中,组合根是自定义的ServiceHostFactory 。 这个答案提供了有关如何做到这一点的更多细节。

@Matthe的post应该回答你的问题。 但是,我想提一下我在代码中注意到的与问题有关的一件事。 您不应该尝试手动解决依赖关系,但应该由容器注入。 我已修改您的代码以显示此行为:

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

您需要确定适合用作合成根的接缝。

对于WCF,您需要具有创造性 – 您必须创建一个自定义ServiceHostFactory来拦截组成对象根目录的正确位置。

参见本文和Mark Seemann撰写的这篇文章 (“.Net中的dependency injection”一书的作者 – 我认为你会发现这本书非常有用)。

许多免费的DI容器, 如Autofac ,为WCF提供了现成的支持,这可能是最好的方法。

我真的不能足够推荐Seemann的书 – 它详细介绍了这一点。

您可能还会发现有关使用Autofac DI和ASP.Net以及存储库感兴趣的文章。