bguler
bguler

Reputation: 247

RepositoryFactory with Ninject

I'm working on web application (web form). I want to be able to change EntityFrameworkRepositoryFactory to NHibernateRepositoryFactory in the future.

IRepositoryFactory

public interface IRepositoryFactory

{

IProductRepository GetProductRepository();

}

ProductRepository

public class ProductRepository : IProductRepository
{

ExDbContext _db;


public ProductRepository(ExDbContext dbContext)
{

_db = dbContext;

}



public IList<Product> ListProductsByCategoryId(int categoryId)
{

List<Product> productsByCategoryId = _db.Products.Where(x => x.ProductCategoryId == categoryId).ToList();

return productsByCategoryId;

}

}

And there is EntityFrameworkRepositoryFactory.

class EntityFrameworkRepositoryFactory:IRepositoryFactory

{

ExDbContext _db;

public EntityFrameworkRepositoryFactory(ExDbContext dbContext)

{

_db = dbContext;

//

// TODO: Add constructor logic here

//

}

public IProductRepository GetProductRepository()

{

return new ProductRepository(_db);

}

}

How can i make easy for changing this in future ? I want use ninject for access EntityFrameworkRepositoryFactory but I'm stuck. Is there any example for this ?

Thanks.

Upvotes: 0

Views: 219

Answers (1)

Frank
Frank

Reputation: 4481

We will add Ninject to your web application, fix your repository classes and add some Ninject modules to configure dependency injection:

  1. Install Ninject. You can do this easily using the Package Manager Console: Install-Package Ninject.Web -dependencyVersion Highest

  2. Remove your RepositoryFactory. Delete IRepositoryFactory and EntityFrameworkRepositoryFactory. You don't need them. Ninject will create a Repository and provide the dependencies as soon as your application asks for them. You need factories only to have better control of an object's lifetime.

  3. Fix the repository. Let's make things more conventional and use an IEnumerable<Product> to return a read-only collection of products as result of our query. We also use Get as a prefix, as most repository patterns do:

    public interface IProductRepository 
    {
        IEnumerable<Product> GetProductsByCategoryId(int categoryId);
    }
    
    class EfProductRepository : IProductRepository
    {
        private readonly ExDbContext db;
    
        public EfProductRepository(ExDbContext dbContext)
        {
            this.db = dbContext;
        }
    
        public IEnumerable<Product> GetProductsByCategoryId(int categoryId)
        {
            var productsByCategoryId = this.db
                .Products
                .Where(x => x.ProductCategoryId == categoryId)
                .ToArray();
    
            return productsByCategoryId;
        }
    }
    
  4. Create a Ninject module. We need to bind our repository implementation to its interface. The Entity Framework DbContext uses the "Unit of Work" pattern, so we also need to make sure that our entity context instances are going to be disposed as soon as a request ends. We could do this using a context factory and the using directive, but we can also use the "Request Scope" of Ninject as it's easier:

    public class EfRepositoryModule : NinjectModule
    {
        public override void Load()
        {
            this.Bind<IProductRepository>().To<EfProductRepository>();
            this.Bind<ExDbContext>().ToSelf().InRequestScope();
        }
    }
    

    At first, we bind IProductRepository to our concrete implementation. Thereby, whenever a component needs a product repository, Ninject will create an instance of EfProductRepository and use that.

    Then we tell Ninject to bind ExDbContext to itself and use the request scope. All dependencies on ExDbContext will be served by one single instance of this class during a request, and this instance is going to be disposed when the request ends.

  5. Load the module. In App_Start/NinjectWebCommon.cs update the following method:

    private static void RegisterServices(IKernel kernel)
    {
        kernel.Load<EfRepositoryModule>();
    }
    
  6. Add dependencies to your pages. In every page where you need to show products, add the following property:

    [Inject]
    public IProductRepository ProductRepository { get; set; }
    

    We need to use property injection or method injection here, because Web Pages doesn't support constructor injection (which should usually be favored). The Inject attribute tells Ninject that we have a dependency here that we want to be injected.

  7. Add a module for NHibernate later on.

    public class NHibernateRepositoryModule : NinjectModule
    {
        public override void Load()
        {
            this.Bind<IProductRepository>().To<NHibernateProductRepository>();
            // Bind whatever else you need when working with NHibernate
        }
    }
    
    // NinjectWebCommon
    private static void RegisterServices(IKernel kernel)
    {
        kernel.Load<EfRepositoryModule>();
    }
    

Upvotes: 3

Related Questions