Как использовать Простой инжектор для хранилища на бизнес-уровне
Я хотел бы, чтобы в моем слое MVC вообще не было никаких репозиториев.
У меня общий EFRepository
, IRepository
а также PASContext
(который наследуется от DbContext) в моем уровне проекта DAL.
Я установил Simple Injector с быстрым запуском в моем проекте MVC, и это позволяет мне получить в конструкторе каждого контроллера нужный мне репозиторий.
Но в моем решении у меня также есть проект BLL, и я хочу, чтобы слой MVC общался только со слоем BLL, поскольку это архитектура проекта, и в будущем я хотел бы добавить логику в классы в слое BLL.
Также я не хочу создавать контекст в моем слое BLL, но репозиторий не имеет конструктора, который принимает 0 аргументов, это мой ProductBLL
учебный класс:
public class BLLProducts
{
IRepository<Product> ProductRepository;
public BLLProducts(EFRepository<Product> Repository)
{
ProductRepository = Repository;
}
public ICollection<Product> getAll()
{
return ProductRepository.All().ToList();
}
}
Как я могу начать BLLProduct
класс из контроллера или из unitTest без создания хранилища / контекста? так что я могу сохранить свою абстракцию здесь.
Я знаю, что мне нужно как-то использовать простой инжектор здесь, я просто не знаю как.
1 ответ
С точки зрения контроллера, это просто вопрос введения BLLProducts
в это, как это:
// constructor
public HomeController(BLLProducts products) {
this.products = products;
}
С точки зрения модульного тестирования, предоставление контроллерам зависимости от конкретных классов является неоптимальным (это нарушает принцип инверсии зависимости). Это субоптимально, так как теперь вам нужно создать BLLProducts
экземпляр и создать его экземпляр с DbContext
, но этот DbContext является специфическим для Entity Framework, который зависит от базы данных. Это делает тестирование сложнее и медленнее. Вы хотите, чтобы ваши модульные тесты выполнялись без базы данных.
Таким образом, решение этого состоит в том, чтобы скрыть это BLLProducts
класс за абстракцией. Простой способ сделать это - извлечь интерфейс из этого класса:
public interface IBLLProducts {
ICollection<Product> getAll();
}
Это делает модульное тестирование контроллеров намного проще. Единственное, что вам нужно сделать, это позволить этому зависеть от этого нового интерфейса:
public HomeController(IBLLProducts products) {
this.products = products;
}
Вам нужно будет зарегистрировать это IBLLProducts
интерфейс в простом инжекторе:
container.Register<IBBLProducts, BLLProducts>();
У всей этой модели есть свои недостатки. Например, хотя Simple Injector может создавать и использовать DbContext для вас, где вы вызываете SubmitChanges? Делать это, когда веб-запросы заканчиваются, довольно плохая идея. Единственное удобное решение, которое я нашел для этого, - перейти на более твердую архитектуру. Например, взгляните на этот вопрос.