Как использовать Простой инжектор для хранилища на бизнес-уровне

Я хотел бы, чтобы в моем слое 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? Делать это, когда веб-запросы заканчиваются, довольно плохая идея. Единственное удобное решение, которое я нашел для этого, - перейти на более твердую архитектуру. Например, взгляните на этот вопрос.

Другие вопросы по тегам