Get ninject factory extension to allow factory parameters be passed to dependencies
Asked Answered
A

3

7

Using the Ninject Factory extension, you can automatically generate factories, and let the factory pass parameters to the class' constructor. The following test passes:

public interface IBar
{
    int Foo { get; }
}

public class Bar : IBar
{
    int _foo;
    public Bar(int foo) { _foo = foo; }
    public int Foo { get { return _foo; } }
}

public interface IBarFactory
{
    IBar CreateTest(int foo);
}

[Test]
public void ExecuteTest()
{
    var kernel = new StandardKernel();
    kernel.Bind<IBar>().To<Bar>();
    kernel.Bind<IBarFactory>().ToFactory();
    var factory = kernel.Get<IBarFactory>();
    var actual = factory.CreateTest(42);
    Assert.That(actual, Is.InstanceOf<Bar>());
}

However, in my particular problem, I would like it to pass the factory arguments to a dependency of the class I'm constructing, not the class itself, like this:

public interface IBarContainer
{
    IBar Bar { get; }
}

public class BarContainer : IBarContainer
{
    IBar _bar;
    public BarContainer(IBar bar) { _bar = bar; }
    public IBar Bar { get { return _bar; } }
}

public interface ITestContainerFactory
{
    IBarContainer CreateTestContainer(int foo);
}

[Test]
public void ExecuteTestContainer()
{
    var kernel = new StandardKernel();
    kernel.Bind<IBar>().To<Bar>();
    kernel.Bind<IBarContainer>().To<BarContainer>();
    kernel.Bind<ITestContainerFactory>().ToFactory();
    var factory = kernel.Get<ITestContainerFactory>();
    var actual = factory.CreateTestContainer(42);
    Assert.That(actual.Bar, Is.InstanceOf<Bar>());
}

This test fails with the message:

Ninject.ActivationException : Error activating int No matching bindings are available, and the type is not self-bindable. Activation path:
3) Injection of dependency int into parameter foo of constructor of type Bar
2) Injection of dependency IBar into parameter bar of constructor of type BarContainer
1) Request for IBarContainer

Is there a way to make the factory figure out that I want to use the passed 'foo' argument when resolving the 'Bar' dependency?

Anterior answered 27/6, 2012 at 10:54 Comment(0)
S
5

From version 3.2.0 of Ninject.Extensions.Factory this is supported natively, using:

Ninject.Extensions.Factory.TypeMatchingArgumentInheritanceInstanceProvider

You can use it like this:

kernel.Bind<IxxxFactory>()
   .ToFactory(() => new TypeMatchingArgumentInheritanceInstanceProvider());

If you look at the source code, it's based on the previous answer.

Stenographer answered 14/8, 2015 at 8:43 Comment(1)
Thank you for this piece of information! This should be the accepted answer as it uses built in functionality.Uredo
O
5

Hy, The default instance provider does not use constructor arguments which are inherited. You can change this behavior by writing your own instance provider like the following:

public class CustomInstanceProvider : StandardInstanceProvider {
    protected override ConstructorArgument[] 
        GetConstructorArguments(MethodInfo methodInfo, object[] arguments) 
        {
            var parameters = methodInfo.GetParameters();
            var constructorArguments = 
                new ConstructorArgument[parameters.Length];
            for (int i = 0; i < parameters.Length; i++)
            {
                constructorArguments[i] = 
                    new ConstructorArgument
                        (parameters[i].Name, arguments[i], true);
            }
            return constructorArguments;
        }
}

Then you only have to instruct ninject to use your own instead of the provided.

Hope that helps

Orchestrate answered 27/6, 2012 at 21:58 Comment(0)
S
5

From version 3.2.0 of Ninject.Extensions.Factory this is supported natively, using:

Ninject.Extensions.Factory.TypeMatchingArgumentInheritanceInstanceProvider

You can use it like this:

kernel.Bind<IxxxFactory>()
   .ToFactory(() => new TypeMatchingArgumentInheritanceInstanceProvider());

If you look at the source code, it's based on the previous answer.

Stenographer answered 14/8, 2015 at 8:43 Comment(1)
Thank you for this piece of information! This should be the accepted answer as it uses built in functionality.Uredo
R
1

If I'm understanding your question correctly, I believe that this Ninject Wiki article has a good example ( Factory interface ) on how to use the new .ToFactory() binding extension, and how to get those generated factories to even create objects who's constructors have parameters.

Rhizocarpous answered 26/10, 2012 at 14:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.