Search code examples
ninject

Ninject cascading named resolution?


I have two objects that support the same interface. Each object has its own configuration object that gets passed as a constructor argument. I want Ninject to use the name of the object to resolve the same of its configuration parameter. Currently, if I do kernel.Get("one") it fails to resolve ThingConfig, even though there is exactly one registered by that name. (EDIT: Fixed example to include ThingConfig binding):

class MyService
{
    public MyService([Named("one")] IThing one, [Named("two")] IThing two) {}
}

class ThingConfig {}

class Thing(ThingConfig cfg) : IThing {}

And in my binder:
Bind<IThing>().To(typeof(Thing)).InSingletonScope().Named("one");
Bind<IThing>().To(typeof(Thing)).InSingletonScope().Named("two");
Bind<ThingConfig>().ToMethod(() => new ThingConfig()).InSingletonScope().Named("one");
Bind<ThingConfig>().ToMethod(() => new ThingConfig()).InSingletonScope().Named("two");

Solution

  • I think I found an acceptable solution involving Named and WhenAnyAncestorNamed.

    I wanted to essentially have a "tag" that identified the scope, so the name fits the bill. I wanted to be able to resolve object by name, or when injected into objects activated by that name. To do that, I had to bind the object twice - once by name, and once for any ancestor with that name:

    Bind(interfaces.ToArray()).To(objectType).InSingletonScope().Named(name);
    Bind(interfaces.ToArray()).ToMethod(
         ctx => ctx.Kernel.Get(ctx.Request.Service, name)).WhenAnyAncestorNamed(name);
    

    If anyone knows a more elegant solution, I'm all ears.