我希望在我的MVC层中根本没有存储库。
我在DAL项目层中有通用的EFRepository
、IRepository
和PASContext
(继承自DbContext)。
我已经在我的MVC项目下安装了Simple Injector,它可以让我在每个控制器的构造函数中获得我想要的存储库。
但在我的解决方案中,我也有BLL项目,我希望MVC层只与BLL层对话,因为这是项目架构,将来我想在BLL层内的类中添加逻辑。
此外,我不想在我的BLL层中创建上下文,但Repository没有接受0个参数的构造函数,这是我的ProductBLL
类:
public class BLLProducts
{
IRepository<Product> ProductRepository;
public BLLProducts(EFRepository<Product> Repository)
{
ProductRepository = Repository;
}
public ICollection<Product> getAll()
{
return ProductRepository.All().ToList();
}
}
如何在不创建存储库/上下文的情况下从控制器或unitTest启动BLLProduct
类?这样我就可以把我的抽象概念留在这里了。
我知道我需要以某种方式使用这里的简单注射器,我只是不知道如何使用。
从控制器的角度来看,只需要将BLLProducts
注入其中,如下所示:
// constructor
public HomeController(BLLProducts products) {
this.products = products;
}
从单元测试的角度来看,让控制器依赖于具体的类是次优的(这违反了依赖反转原则)。这是次优的,因为您现在需要创建一个BLLProducts
实例并用DbContext
实例化它,但这个DbContext是特定于实体框架的,它依赖于数据库。这使得测试更加困难和缓慢。您希望单元测试在没有数据库的情况下运行。
因此,解决方案是将这个BLLProducts
类隐藏在抽象后面。一个简单的方法是从这个类中提取一个接口:
public interface IBLLProducts {
ICollection<Product> getAll();
}
这使得控制器的单元测试更加容易。你唯一要做的就是让它依赖于这个新接口:
public HomeController(IBLLProducts products) {
this.products = products;
}
您需要在Simple Injector:中注册此IBLLProducts
接口
container.Register<IBBLProducts, BLLProducts>();
整个模型仍然有一些缺点。例如,虽然Simple Injector可以为您创建和处理DbContext,但您在哪里调用SubmitChanges?当网络请求结束时这样做是一个非常糟糕的主意。我找到的唯一方便的解决方案是转移到更坚固的体系结构。例如,看看这个问题。