Inject value into injected dependency
Asked Answered
O

2

8

I'm having something like this:

class Root
{
    public Root(IDependency dep)
    {}
}
class Dependency:IDependency
{
    public Dependency(int val)
    {}
}

And I'm trying to obtain a reference to Root using ninject. So i configure it like this

var module = new InlineModule(mod => mod.Bind<IDependency>().To<Dependency>());

var kernel = new StandardKernel(module);

I'd like to inject into Dependency some 'val' value that is known only at the moment of obtaining the Root reference from ninject.

What i'd like to do is something like this:

Kernel.Instance.Get<Root>(With.Parameters.ConstructorArgument("val", 12));

Is something like this possible using ninject 1.0?

Octans answered 28/1, 2010 at 10:30 Comment(0)
C
8

The Parameters.ConstructorArgument in the context only goes one leve deep by default.

One way of passing parameters down multiple levels is by using a ContextParameter, but something then needs to grab that and say - and now we're going to use that as a ConstructorArgument in this case. One such construct is Providers. See this dojo page for details of Providers

So you can do:

    class DependencyProvider : SimpleProvider<Dependency>
    {
        protected override Dependency CreateInstance( IContext context )
        {
            return new Dependency( (int)context.ParentContext.Parameters.GetOne<ContextVariableParameter>( "masterVal" ).Value );
        }
    }

    public static void Main()
    {
        var module = new InlineModule(
            mod => mod.Bind<IDependency>().ToProvider( new DependencyProvider() )
        );

        var kernel = new StandardKernel( new[  ] {module} );

        Root root = kernel.Get<Root>( With.Parameters.ContextVariable( "masterVal", 12 ) ); 
    }

Or you can manage it as follows:

    class RootProvider : SimpleProvider<Root>
    {
        protected override Root CreateInstance( IContext context )
        {
            return new Root( context.Kernel.Get<Dependency>( With.Parameters.ConstructorArgument("val", ( int )context.Parameters.GetOne<ContextVariableParameter>("masterVal").Value )));
        }
    }

    public static void Main()
    {
        var module = new InlineModule(
            mod => mod.Bind<IDependency>().To<Dependency>(), // Optional if ImplictSelfBinding is on
            mod => mod.Bind<Root>().ToProvider( new RootProvider() )
        );

        var kernel = new StandardKernel( new[] {module} );

        Root root = kernel.Get<Root>( With.Parameters.ContextVariable( "masterVal", 12 ) ); 
    }

While you're thinking about this, consider the points I make in this point re separating the concerns if configuration from object binding in this response.

Calendula answered 29/1, 2010 at 13:44 Comment(10)
I think i could do it a bit more simply like: Bind<IDependency>().To<Dependency>().WithConstructorArgument("val", (IContext cont) => cont.ParentContext.Parameters.Get<ConstructorArgumentParameter>("val")); But i don't like using the ParentContext. :( ItOctans
@Silviu: Try it - the shorter the better. It seemed to make sense to me as as doign directly what you were asking, but I couldnt get it to work for me in the context I was trying it.Calendula
@Silviu: Did you get doing it as part of the Bind work out? Iff so, if you want to chuck something that works into the comments, I'll put it into the examples.Calendula
Sorry for the late response. I tried with the parent context. It worked. Not very proud of it. :D Probably my point of view's fault but when I'm defining a binding I'm telling Ninject to use some key value pair. And at that moment for some reason i expected to consider those values for the entire chain of dependencies because that was the context being used. In fact i considered that the context represents the medium based on which Ninject builds things. So once defined for some class it should use that context for all deps. Each dep's binding adding to the same context.Octans
I really don't like that parent thing. Feels like I need to know at the binding level too much stuff about the hierarchy of dependencies. I mean, what if i put another layer between the Root and the Dependency? Then I'll have to modify the binding of the dependency to context.ParentContext.ParentContext and that is some seriously ugly coupling.Octans
I agree with your concerns as you put it. The main reason I feel it is set up as it is is that you definitely dont want to have a global context - in the same way that you're pushed towards sticking things in modules, any passing of stuff down chains during injection should be in a managed way in terms of knowing what you're doing. You' re right to keep your eyes open when doing stuff in this space. In general, you only want to get into context like this as little as possible and use higher level constructs like having one clear interface with one clear thing to bind to where possible.Calendula
Is what you're looking for in the direction of names and/or can you re-angle your requirements in that direction? See #2099592Calendula
@Ruben Bartelink - thanks for the answer. I have a similar issue (#8305976) that Remo has offered an answer for... but im having trouble getting the value of an attribute's constructor argument to the constructor argument of its bound filter. Can you provide an example on that Question?Righthander
@Righthander Unfortunately its hard to work out what you mean from just the comment. If Remo Gloor can't sort it out, I suggest asking another question with a failing example,sorry!Calendula
@Ruben Bartelink - Got it figured out. I think I was choking on the Func<> signature. Not enough coffee I guess. that and I needed to expose the value as a property on the Attribute class. Done deal - now I'm trying to parse a Flags-marked enum value into individual flags. :(Righthander
F
2

With Ninject 3 IParameters (ConstructorArgument is one of them) will now simply be "inherited" to child request when they have ShouldInherit == true (see here).

The solution for this question can now be as simple as:

IResolutionRoot.Get<Root>(new ConstructorArgument("val", 12, true));

where as the true in the ConstructorArguments constructor sets ShouldInherit to true. Also see here

Fulk answered 23/9, 2015 at 14:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.