How to use Simple injector for repository in business layer

917 views Asked by At

I would like that in my MVC layer there will be no Repositories at all.

I've generic EFRepository, IRepository and PASContext (which inherits from DbContext) in my DAL project layer .

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 .

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 .

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 :

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 ? so i can keep my abstraction here.

I know i need to use somehow the Simple injector here, i just dont know how .

1

There are 1 answers

2
Steven On BEST ANSWER

From perspective of the controller, it's just a matter of injecting the BLLProducts into it, like this:

// 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). 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. 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. 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:

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? 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.