如何在业务层中使用Simple注入器作为存储库

时间:2013-12-15 19:39:29

标签: c# asp.net-mvc repository simple-injector business-layer

我希望在我的MVC层中根本没有存储库。

我在DAL项目图层中使用了通用EFRepositoryIRepositoryPASContext(继承自DbContext)。

我已经在我的MVC项目下快速启动了Simple Injector,这让我可以进入我想要的每个控制器的构造函数。

但是在我的解决方案中,我还有BLL项目,我希望MVC层只与BLL层对话,因为这是项目架构,将来我想在BLL层的类中添加逻辑。 / p>

此外,我不想在我的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类?所以我可以在这里保留抽象。

我知道我需要在这里以某种方式使用Simple注入器,我只是不知道如何。

1 个答案:

答案 0 :(得分:1)

从控制器的角度来看,只需要将BLLProducts注入其中,就像这样:

// constructor
public HomeController(BLLProducts products) {
    this.products = products;
}

从单元测试的角度来看,让控制器依赖于具体类是不理想的(它违反了Dependency Inversion Principle)。这是次优的,因为您现在需要创建BLLProducts实例并使用DbContext实例化它,但此DbContext特定于Entity Framework,它依赖于数据库。这使得测试更加困难和缓慢。您希望单元测试在没有数据库的情况下运行。

所以解决这个问题的方法是将这个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?在Web请求结束时执行此操作是一个非常糟糕的主意。我找到的唯一方便的解决方案是转向更加SOLID的架构。例如,请查看this question