Home / .NET / Ninject.Extensions.Factory introduction

Ninject.Extensions.Factory introduction

The new release of Ninject 3.0 comes with a new extension that adds support for factories to Ninject. It supports factory interfaces, Func and Lazy. In this blog post I will explain how they are used.

Why using factories?
The recommended way to use IoC containers is that the composition root of the application is the only place where the container is accessed. Unfortunately many application can’t create everything at once during the application start or at the beginning of a web/wcf request because not everything is known at this moment. Therefore these applications need a way to create new instances using the kernel at a later point. Preferably we want to do this without introducing a reference to the container. This is where factories come into play. Instead of injecting the kernel into classes that need to create new instances we inject a factory. This factory is responsible to create the new instances using the kernel. There are two ways to implement such a factory: A factory interface and as a Func or Lazy.

Factory Interface
The recommended way to add factories is to define an interface containing one or several methods to create the required dependencies as shown by the next code snippet.

public class Foo
{
	private IBarFactroy barFactroy;
	public Foo(IBarFactory barFactory)
	{
		this.barFactory = barFactory;
	}

	public void Do()
	{
		var bar = this.barFactroy.CreateBar();
		...
	}
}

public interface IBarFactory
{
	Bar CreateBar();
}

This interface is declared at the same place as the class that is using it. In the binding configuration it can now be bound using the new ToFactory() method. This tells Ninject that it shall automatically implement a factory class for the specified interface and inject a new instance of this factory into each object that request an instance of the factory interface.

kernel.Bind<IBarFactory>().ToFactory();

Sometimes it is necessary to pass some parameters to the new instance. This can be done very simply by adding those parameters to the factory method. The extension uses the convention that you have to use the same parameter names in the factory like you did in the constructor of the created object. The order of the parameters in the factory method and constructor do not have to match.

public class Foo
{
	private IBarFactroy barFactroy;
	public Foo(IBarFactory barFactory)
	{
		this.barFactory = barFactory;
	}

	public void Do(int x, int y)
	{
		var bar = this.barFactroy.CreateBar(x, y);
		...
	}
}

public interface IBarFactory
{
	Bar CreateBar(int x, int y);
}

public class Bar
{
	public Bar(int y, int x)
	{
	}
}

foo.Do(1, 2); // Creates a Bar instance with x = 1, y = 2

Behind the scenes Ninject will create a proxy that implements the specified factory interface and intercept all methods so that the proxy behaves like the following implementation of the factory interface:

public class BarFactory : IBarFactory
{
	private IResolutionRoot resolutionRoot;
	public BarFactory(IResolutionRoot resolutionRoot)
	{
		this.resolutionRoot = resolutionRoot;
	}

	public Bar CreateBar(int y, int x)
	{
		return this.resolutionRoot.Get<Bar>(
			new ConstructorArgument("y", y),
			new ConstructorArgument("x", x));
	}
}

Factory Interface – Named Bindings
Sometimes there is the need to create differnet instances of an interface using named bindings. The default instace provider of the extension has the convention that it tries to return an instance using a named binding whenever a method starts with “Get”. E.g. IFoo GetMySpecialFoo() is equal to

resolutionRoot.Get<IFoo>("MySpecialFoo");

Custom instance provider
In some cases the default instance provider doesn’t meet your requirements. In this case you can do your own implementation with a custom behavior. This is done by implementing the IInstanceProvider interface:

    /// <summary>
    /// Provides instances to the interceptor.
    /// </summary>
    public interface IInstanceProvider
    {
        /// <summary>
        /// Gets an instance for the specified method and arguments.
        /// </summary>
        /// <param name="instanceResolver">The instance resolver.</param>
        /// <param name="methodInfo">The method info of the method that was called on the factory.</param>
        /// <param name="arguments">The arguments that were passed to the factory.</param>
        /// <returns>The newly created instance.</returns>
        object GetInstance(IInstanceResolver instanceResolver, MethodInfo methodInfo, object[] arguments);
    }

In most cases it is easier to derive from the StandardInstanceProvider and overload the required methods to change the behavior. It implements the GetInstances class for you and handles the the special cases of IEnumerable, ICollection, IList and arrays for you and provides the following methods that can be overriden to specify which type, parameters, name and condition is used to resolve the instance:

  • protected virtual Type GetType(MethodInfo methodInfo, object[] arguments)
    This method can be used to override the default behavior that the resolved type is the return type of the executed method.
  • protected virtual string GetName(MethodInfo methodInfo, object[] arguments)
    Here you can override the name. The default behavior is described in the previous chapter.
  • protected virtual ConstructorArgument[] GetConstructorArguments(MethodInfo methodInfo, object[] arguments)
    Override this method in case you need another than the default convention for parameters. The default implementation will create a constructor argument for each parameter using the same parameter name as the one of the factory method.
  • protected virtual Func GetConstraint(MethodInfo methodInfo, object[] arguments)
    In case you want to to use a constraint you need to override this method. The default implementation doesn’t use constraints.

Func
The second way to add factories is to inject a Func to the class that needs to create a new object. Like the factory interface it supports arguments too. But since a Func gives you absolutely no information about the parameters you have to pass, I recommend not using Func unless it takes no arguments. Even if it takes no arguments I personally think factory interfaces is the cleaner way to add factories. You have to write more code but the readability is better than with Func.

public class Foo
{
	private Func<Bar> barFactroy;
	public Foo(Func<Bar> barFactory)
	{
		this.barFactory = barFactory;
	}

	public void Do()
	{
		var bar = this.barFactroy();
		...
	}
}

That’s everything you have to do in this case. There is no need to create a special binding for the Func.

Lazy
Sometimes the creation of a dependency must be postponed because it uses a lot of resources or it is heavy to create and rarely used. In this case you can inject Lazy instead of IDependency. This way, the creation of the dependency will be postponed until the Value of the Lazy is accessed the first time. This instance will be reused for all following accesses to Value.

public class Foo
{
	private Lazy<Bar> lazyBar;
	public Foo(Lazy<Bar> bar)
	{
		this.lazyBar = bar;
	}

	public void Do()
	{
		var bar = this.lazyBar.Value;
		...
	}
}