Ninject summon graphs with argument
Question
Here is my problem. I have a presenter class, lets call it 'Presenter' that takes an IDataSource as a constructor argument. There are different implementations of the IDataSource interface. I would like to be able to pass some argument to Ninject and based on that argument one of several IDataSource implementations should by used. I've provided some sample code below. I think that my solution is really ugly and that there must be a smarter, cleaner way to do this. How are you guys solving this type of problem?
Here is my sample code
public class Presenter
{
public Presenter(IDataSource dataSource)
{
DataSource = dataSource;
}
private IDataSource DataSource { get; set; }
public List<string> GetData()
{
return DataSource.GetAll();
}
}
public class InMemoryDataSource : IDataSource
{
public List<string> GetAll()
{
return new List<string> {"a", "b"};
}
}
public class DbDataSource : IDataSource
{
public List<string> GetAll()
{
return new List<string> { "1", "2" };
}
}
public interface IDataSource
{
List<string> GetAll();
}
public class Module : NinjectModule
{
public override void Load()
{
Bind<Presenter>().To<Presenter>().Named("Db");
Bind<Presenter>().To<Presenter>().Named("InMemory");
Bind<IDataSource>().To<InMemoryDataSource> ().WhenParentNamed("InMemory");
Bind<IDataSource>().To<DbDataSource>().WhenParentNamed("Db");
}
}
[Test]
public void Run()
{
using (var kernel = new StandardKernel(new Module()))
{
var p = kernel.Get<Presenter>(x => x.Name == "InMemory");
foreach(var s in p.GetData())
{
Console.Out.WriteLine(s);
}
}
}
Solution
This depends on what you want to do. I assume that you want to use a different db for testing than for production. In this case would create the module with the production configuration in mind and simply Rebind everything for testing:
public class Presenter
{
public Presenter(IDataSource dataSource)
{
DataSource = dataSource;
}
private IDataSource DataSource { get; set; }
public List<string> GetData()
{
return DataSource.GetAll();
}
}
public class InMemoryDataSource : IDataSource
{
public List<string> GetAll()
{
return new List<string> {"a", "b"};
}
}
public class DbDataSource : IDataSource
{
public List<string> GetAll()
{
return new List<string> { "1", "2" };
}
}
public interface IDataSource
{
List<string> GetAll();
}
public class Module : NinjectModule
{
public override void Load()
{
Bind<Presenter>().To<Presenter>();
Bind<IDataSource>().To<DbDataSource>();
}
}
[Test]
public void Run()
{
using (var kernel = new StandardKernel(new Module()))
{
kernel.Rebind<IDataSource>().To<InMemoryDataSource>();
var p = kernel.Get<Presenter>();
foreach(var s in p.GetData())
{
Console.Out.WriteLine(s);
}
}
}