Ninject passing in constructor values
Asked Answered
I

5

13

With Ninject, how do you configure the kernel so I can define what constructor values are passing into the instantiation of an object?

I have the following configured in a module:

Bind<IService1>()
    .To<Service1Impl>()
    .InSingletonScope()
    .Named("LIVE");
Bind<IService2>()
    .To<Service2Impl>()
    .InSingletonScope()
    .Named("LIVE")
    .WithConstructorArgument(
        "service1", 
        Kernel.Get<IService1>("LIVE"));

Service2Impl takes a constructor parameter of IService1 but I want this to come from the container. I also want to have named bindings as my code will be targeting different versions at runtime.

This seems to work but is it the right way to achieve what I want to do? Should I be achieving without the use of named bindings and wiring different configuration modules into the kernel?

EDIT

I have used the ToMethod() method now to specify a delegate to call on request of a specific type. This seems a bit nicer as I'll get compile time warnings if the constructor configuration is wrong rather than having to know the name of the parameter I am passing first.

Thanks

Ivetteivetts answered 19/5, 2011 at 22:18 Comment(0)
I
14

I used ToMethod in the end, which allowed me to construct the required instance with constructors in order to maintain compile time errors.

For example:

.ToMethod(Func<IContext, T> method)

Bind<IWeapon>().ToMethod(context => new Sword());
Ivetteivetts answered 1/6, 2011 at 17:6 Comment(2)
Much prefer this syntax to .WithConstructorArgument, compiler catches refactoring errors. +1Chadchadabe
Did you seriously have an application calling for a Weapon interface and Sword object?Upstream
P
18

I would recommend the WithConstructorParameter overload that takes a lambda like so:

Bind<IService2>()
    .To<Service2Impl>()
    .InSingletonScope()
    .Named("LIVE")
    .WithConstructorArgument(
        "service1", 
        ctx => ctx.Kernel.Get<IService1>("LIVE"));

This will ensure that that the resolution of IServive1 happens at the time of activation of Service2Impl and not at startup when the container is created. Whilst in your case it doesn't really matter as Service1Impl is singleton, there could be side effects on doing it in the way you originally wrote it:

  • The binding for dependency that is injected by WithConstructorArgument has to already exist. This implies that all bindings have to done in a particular order. This creates can get tricky when there are multiple modules involved.

  • Scoping issues can arise when custom scope is used. Ninject 2.0 introduced cache and collect scope management, binding to a constant is very likely to throw that into disarray.

Pelletier answered 20/5, 2011 at 6:0 Comment(0)
I
14

I used ToMethod in the end, which allowed me to construct the required instance with constructors in order to maintain compile time errors.

For example:

.ToMethod(Func<IContext, T> method)

Bind<IWeapon>().ToMethod(context => new Sword());
Ivetteivetts answered 1/6, 2011 at 17:6 Comment(2)
Much prefer this syntax to .WithConstructorArgument, compiler catches refactoring errors. +1Chadchadabe
Did you seriously have an application calling for a Weapon interface and Sword object?Upstream
W
6

It seems you're looking at this the wrong way. Ninject will inject service 1 automatically into service 2 if it has it as constructor argument. There is not need for WithConstructorArgument in this case.

If there are multiple IService1 you should go for conditions. E.g. WhenParentNamed(...)

Wader answered 23/5, 2011 at 18:12 Comment(0)
N
0

Maybe the Providers can help you. Bind IService2 To a Provider. and in the Create method of Provider, use Kernel.Get("LIVE") to create the Service2Impl instance.

see the following link to know how to use Provider https://github.com/ninject/ninject/wiki/Providers%2C-Factory-Methods-and-the-Activation-Context

Neutrality answered 20/5, 2011 at 1:19 Comment(1)
Thanks, I saw that. Thought it was a bit too much code and as it says in the link you shared the ToMethod is a leaner version of a provider.Ivetteivetts
H
0

I think ToConstant() is cleaner, the InSingletonScope is implicit:

Bind<IService2>().ToConstant(new Service2Impl(argument)))
                 .Named("LIVE");
Halfmast answered 20/2, 2014 at 20:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.