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; ... } }
Why have Lazy at all, if you inject Func, that would be lazy as well by default or inject and other factory. This is what Guice actually does so you just use a factory and the bindings you can still bind to a singleton scope such that the factory returns the same instance over and over and over which allows you in one place to inject the factory where there was a circular dependency(ick) and in another where there is no circular dependency, you can still do normal injection.
It’s a language feature. So why not support it? There is not even one line of code necessary to support this feature.
In situations where you would normally inject a new instance of the created object but you want to postpone its creation it simplyfies this task using a Lazy instead of using a Func. But you are free to use Func instead and make sure you get the same instance every time you want.
BTW Factories of any kind shouldn’t be used to work around circular dependencies. Better fix the actual problem. Circular dependencies are never a good design and normally indicate that SRP is violated somehow.
How does the factory and it’s instantiated objects lifetime get managed? How would one set it’s lifetime to InRequestScope() so that it would be automatically disposed when the request is completed?
@Erik
The default Ninject scoping mechanism is used. E.g. if the binding for the created object is InRequestScope then it is disposed at the end of the request.
Is the ToFactory() method included in Ninject pre-release 3? I cannot locate the method to use it.
Hy,
It is in the Factory extension.
Have fun
Just tried this out for the first time – great work!
[…] I’m looking at the Ninject Factory extension at the following link: http://www.planetgeek.ch/2011/12/31/ninject-extensions-factory-introduction/ […]
[…] I’m looking at the Ninject Factory extension at the following link: http://www.planetgeek.ch/2011/12/31/ninject-extensions-factory-introduction/ […]
[…] http://www.planetgeek.ch/2011/12/31/ninject-extensions-factory-introduction/ for more information about factories. Also have a look at the InCallScope of the named scope […]
[…] also: http://www.planetgeek.ch/2011/12/31/ninject-extensions-factory-introduction/ Tagged: cninjectquestions /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO […]
What if Bar was just one implementation of an interface IBar? Would we create factories for each concrete implementation, or just one for the interface? I guess we would need a constructor signature in the interface to use the same factory for each implementation.
@Patrick Stephansen
Use Named Bindings as described in the blog post
Thanks. I didn’t quite get it from the blog but this helped: http://github.com/ninject/ninject.extensions.factory/wiki/Factory-interface%3A-Referencing-Named-Bindings.
I don’t understand the first example in the Factory interface example. Why would you even have a factory that always returned the same type?
public interface IBarFactory
{
Bar CreateBar();
}
In what scenario would you do that?
Hi, Why not? Is is about a factory which creates a new instance of a Bar class every time you call it. This allows you to create the object over the factory when needed.
Great post!
I still have a question. In my Application i need to resolve types that need to be identified at run time. I just know the “Type” to be resolved. But with this factory you need to call the method that creates a specific type. IS there any workaround?
Have you tried https://github.com/ninject/Ninject.Extensions.Factory/wiki/Factory-interface:-custom-instance-providers ?
This is just copy paste from github documentation.