If I have a class, which has dual dependencies on the same type (needs two different instances), if the only difference between the instances is a deeper dependency, what's the best way to have Ninject perform DI and keep the two graphs separate?
Example object graph:
foo → ClassA → ClassB
bar → ClassA → ClassB
Class C's constructor:
public class C
{
    public C(ClassB foo, ClassB bar) { … }
}
So how do I make sure that the ClassB instantiated with foo gets supplied as the ClassB dependancy foo, and bar… bar?
Just for some background, I had some requirements change, so I need to replace a write-only repository (IAdd) with a composite write-only repository
public class CompositeWriteRepository<T> : IAdd<T>
{
    public CompositeWriteRepository(IAdd<T> foo, IAdd<T> bar, Func<T, bool> descriminator) { ... }
    public Add(T entity)
    {
        if (descriminator(entity)) {
            foo.Add(entity);
        } else {
            bar.Add(entity);
        }
    }        
}
With mocking, that was easy enough, I could just inject using names:
 kernel.Bind<IAdd<EntityType>>().To<fooRepository>().Named("foo");
 kernel.Bind<IAdd<EntityType>>().To<barRepository>().Named("bar");
 kernel.Bind<IAdd<EntityType>>().To<CompositeWriterRepository<EntityType>>()
    .WithConstructorArgument("foo", x => x.Kernel.Get<IAdd<EntityType>>("foo")
    .WithConstructorArgument("bar", x => x.Kernel.Get<IAdd<EntityType>>("bar");
The problem comes when I use the real repositories; foo and bar ultimately write to files so they need different file names.  Since they're StreamWriter repositories, one of their dependencies actually gets the two different file names.
string FileName → FileStreamWriterFactory → StreamRepository → CompositeRepository
The only way I've found thus far to construct things is to make a named FileName, named FileStreamWriterFactory, named StreamRepository × 2 (once for foo and once for bar). This seems like a lot of work, so I hope there's a better solution.
I can re-architect if needed, it felt like an elegant way to quickly add in seperating the entries when the requirements changed. I realize my classes all are quite specific, but I think single responsibility would support this generally and in my case we write a bunch of small applications and have more requests the we can fulfill so its a good way to have lot's of re-usable code laying around that I basically just need to re-configure for different tasks.
Solution
Remo Gloor should get credit; his is probably the best practice.
What I actually did was create a new extension
public static bool WhenAnchester(this IRequest request, Func<IRequest, bool> conditions)
{
    var parentContext = request.ParentContext;
    if (parentContext == null) {
            return false;
    }
    return conditions(parentContext.Request) || 
        parentContext.Request.WhenAnchester(conditions);
} 
This then let me easily control which file get injected into which repository.
kernel.Bind<string>().ToConstant("Foo.txt")
    .When(x => x.Target.Name == "filepath" && 
              x.WhenAnchester(t => t.Target != null && t.Target.Name == "Dest1"));
kernel.Bind<string>().ToConstant("Bar.txt")
    .When(x => x.Target.Name == "filepath" &&
               x.WhenAnchester(t => t.Target != null && t.Target.Name == "Dest2"));
There's probably a better solution, so I wouldn't necessary recommend this for others, but its working well for me.
Yes there is a better way
See https://github.com/ninject/ninject/commit/60443badf4ef840531c93e9287b154a9bba337c2
It's 3.0 but IsAnyAnchestorNamed can also be used with 2.2 from a When condition.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With