views:

145

answers:

3

I am very new to Ninject and am trying Ninject 2 with MVC and Linq. I have a SqlProductRepository class and all I want to know is what's the best way of passing the connectionstring in the constructor if I am injecting the Repository object in the controller.

public class SqlProductRepository:IProductRepository
{
    private Table<Product> productsTable;

    public SqlProductRepository(string connectionString)
    {
      productsTable = (new DataContext(connectionString)).GetTable<Product>();   
    }

    public IQueryable<Product> Products
    {
        get { return productsTable; }
    }
}

This is my ProductController class where I am injecting the Repository:

  public class ProductsController : Controller
{
    private int pageSize = 4;
    public int PageSize { get { return pageSize; } set { pageSize = value; } }  

    IProductRepository _productsRepository;

    [Inject]
    public ProductsController(IProductRepository productRepository)
    {
        _productsRepository = productRepository;
    }

    public ViewResult List(int page)
    {
        return View(_productsRepository.Products
                                       .Skip((page - 1) * pageSize)
                                       .Take(pageSize)
                                       .ToList()
                    );
    }
}

Can somebody please guide me regarding this?

+6  A: 

You can set it up in your binding


_kernel.Bind<IProductRepository>()
       .To<SqlProductRepository>()
       .WithConstructorArgument("connectionString",yourConnectionString );
Ian Davis
A: 

You're doing:

new DataContext(connectionString)

in your code - this is the very newing and binding to classes you're trying to push out of your code by using a DI container. At the very least, consider adding an IConnectionStringSelector interface or something like that. You dont want to have 20 Bind calls for 20 repositories - you want a higher level abstraction than that.

I'd suggest the besdt solution is that you should be demanding either an IDataContext or an IDataContextFactory in the constructor instead and letting that worry about it.

Ruben Bartelink
A: 

You could supply the connection string as a constructor argument when binding the SqlProductRepository to the IProductRepository interface.

public class LinqToSqlModule : NinjectModule
{
    public override void Load()
    {
        Bind<IProductRepository>().To<SqlProductRepository>()
            .WithConstructorArgument(connectionString, "connectionstring");
    }
}

I would suggest a slightly different approach. First of all, you might want to create a binding for the DataContext class in the kernel. You could do so by using a provider class to create your DataContext passing the connection string as an argument to its constructor. Then you bind the DataContext to the DataContextProvider.

public class DataContextProvider : Provider<DataContext>
{
    protected override DataContext CreateInstance(IContext context)
    {
        string connectionString = "connectionstring";
        return new DataContext(connectionString);
    }
}

public class LinqToSqlModule : NinjectModule
{
    public override void Load()
    {
        Bind<DataContext>().ToProvider<DataContextProvider>();
        Bind<IProductRepository>().To<SqlProductRepository>();
    }
}

Next modify the constructor of SqlProductRepository class to accept a DataContext object instead.

public class SqlProductRepository : IProductRepository
{
    private readonly DataContext context;

    public ProductRepository(DataContext context)
    {
        this.context = context;
    }

    public IQueryable<Product> Products
    { 
        get { return context.GetTable<Product>(); }
    }
}

By the way you don't have to decorate your constructor with the Inject attribute. Ninject will select the constructor with the most parameters by default.

mrydengren