How to use Simple injector, Repository and Context - code first

jony89 picture jony89 · Dec 15, 2013 · Viewed 10.1k times · Source

I'm trying to use Simple Injector to create my repository and use it in the Business logic layer ( also i want to use PerWebRequest method ) .

In the DAL layer i have :

public interface IRepository<T> where T : class
{
    void Add(T entity);
    void Delete(T entity);
    void Delete(int id);
    void Update(T entity);
    T GetById(int Id);
    IQueryable<T> All();
    IEnumerable<T> Find(Func<T, bool> predicate);
}

and :

public class EFRepository<T> : IRepository<T>, IDisposable where T : class
{
    #region Members
    protected DbContext Context { get; set; }
    protected DbSet<T> DbSet { get; set; }
    #endregion

    #region Constructors

    public EFRepository(DbContext dbContext)
    {
        if (dbContext == null)
            throw new ArgumentNullException("dbContext");
        Context = dbContext;
        DbSet = Context.Set<T>();
    }

and my context :

public class PASContext : DbContext, IDbContext
{
    public DbSet<Product> Products { get; set; }
    public DbSet<User> Users { get; set; }

    public PASContext()
        : base("PostAndSell")
    { }
}

As you can see EFRepository has only one constructor that takes one argument - this is because i want to use Simple Injector to create an instance of the context and pass it to the repository while it is created .

In the BLL i have a class ProductBLL and i want to get all products in that class (with some GetAll method) from the database and pass it, lets say to HomeController .

I really need someone to talk me through this .

I started by installing the right packages from the nuger (Simple Injector and Simple Injector ASP.NET Integration)

also in my global.asax.cs file, under Application_Start() function I`ve added :

var container = new SimpleInjector.Container();

container.RegisterPerWebRequest<IRepository<Product>, EFRepository<Product>>();

but where do i create the Context instance ? and how can i access it in the business layer ?

Answer

Steven picture Steven · Dec 15, 2013

Since you will probably have many IReposotory<T> implementations (for Product, Customer, Employee, etc), it's better make a single open generic registration for IRepository<T> like this:

container.Register(typeof(IRepository<>), typeof(EFRepository<>), Lifestyle.Scoped);

Where the scoped lifestyle is defined as:

container.Options.DefaultScopedLifestyle = new WebRequestLifestyle();

This registration ensures that Simple Injector will return a EFRepository<Product>, every time a IRepository<Product> is requested, an EFRepository<Customer> for IRepository<Customer>, and so on, and so on.

Since you want the same DbContext instance to be used over all repositories within the same request, you should also register the DbContext with the scoped Lifestyle:

container.Register<DbContext, PASContext>(Lifestyle.Scoped);

In the BLL i have a class ProductBLL and i want to get all products from the database and pass it to, lets say HomeController

In that scenario, this ProductBLL seems like a useless abstraction to me. If all it does is passing data through, you can as easily let your HomeController depend on IRepository<Product> directly.