简体   繁体   English

如何将简单注入器用于业务层中的存储库

[英]How to use Simple injector for repository in business layer

I would like that in my MVC layer there will be no Repositories at all. 我希望在我的MVC层中根本没有存储库。

I've generic EFRepository , IRepository and PASContext (which inherits from DbContext) in my DAL project layer . 我在DAL项目层中具有通用的EFRepositoryIRepositoryPASContext (从DbContext继承)。

I've installed Simple Injector with quick start under my MVC project and thats allows me to get in the constructor of each controller the repository i want . 我已经在我的MVC项目下以快速入门安装了Simple Injector,这可以让我进入每个控制器的构造函数中我想要的存储库。

But in my solution i have also BLL project and i want MVC layer to talk only with the BLL layer, as this is the project architecture and in the future i would like to add logic in the classes within the BLL layer . 但是在我的解决方案中,我也有BLL项目,并且我希望MVC层仅与BLL层通信,因为这是项目体系结构,将来我想在BLL层的类中添加逻辑。

Also i don't want to create a context in my BLL layer, but the Repository has no constructor which takes 0 arguments, this is my ProductBLL class : 我也不想在我的BLL层中创建上下文,但是存储库没有带0参数的构造函数,这是我的ProductBLL类:

public class BLLProducts
{
    IRepository<Product> ProductRepository;

    public BLLProducts(EFRepository<Product> Repository)
    {
        ProductRepository = Repository;
    }

    public ICollection<Product> getAll()
    {
        return ProductRepository.All().ToList();
    }
}

How can i initiate the BLLProduct class from a controller or from a unitTest without creating a repository/context ? 如何在不创建存储库/上下文的情况下从控制器或从unitTest初始化BLLProduct类? so i can keep my abstraction here. 这样我就可以在这里保留我的抽象了。

I know i need to use somehow the Simple injector here, i just dont know how . 我知道我需要在这里使用简单注入器,我只是不知道如何使用。

From perspective of the controller, it's just a matter of injecting the BLLProducts into it, like this: 从控制器的角度来看,只需将BLLProducts注入其中即可,如下所示:

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

From a unit testing perspective, letting the controllers depend on concrete classes is suboptimal (it violates the Dependency Inversion Principle ). 从单元测试的角度来看,让控制器依赖于具体的类是次优的(这违反了Dependency Inversion Principle )。 This is sub optimal, since you now need to create a BLLProducts instance and instantiate it with a DbContext , but this DbContext is specific to Entity Framework, which depends on a database. 这是次优的,因为你现在需要创建一个BLLProducts实例,并用它实例DbContext ,但这种的DbContext是特定于实体框架,它依赖一个数据库。 This makes testing harder and slower. 这使测试变得越来越困难。 You want your unit tests to run without a database. 您希望单元测试在没有数据库的情况下运行。

So the solution to this is to hide this BLLProducts class behind an abstraction. 因此,解决方案是将此BLLProducts类隐藏在抽象后面。 A simple way to do this is extract an interface out of this class: 一种简单的方法是从此类中提取接口:

public interface IBLLProducts {
    ICollection<Product> getAll();
}

This makes unit testing the controllers much easier. 这使得对控制器进行单元测试变得更加容易。 The only thing you have to do is let it depend on this new interface: 您要做的唯一一件事就是让它依赖于此新接口:

public HomeController(IBLLProducts products) {
    this.products = products;
}

You will need to register this IBLLProducts interface in Simple Injector: 您将需要在Simple Injector中注册此IBLLProducts接口:

container.Register<IBBLProducts, BLLProducts>();

This whole model still has some downsides to it. 整个模型仍然有一些缺点。 For instance, although Simple Injector can create and dispose a DbContext for you, where do you call SubmitChanges? 例如,尽管Simple Injector可以为您创建和处置DbContext,但您在哪里调用SubmitChanges? Doing this when the web requests ends is a pretty bad idea. 在网络请求结束时执行此操作是一个坏主意。 The only convenient solution I found for this is to move to a more SOLID architecture. 我为此找到的唯一方便的解决方案是迁移到更坚固的体系结构。 For instance, take a look at this question . 例如,看看这个问题

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM