In the previous article, we discussed how to use Unity Container for Dependency Injection and we also tested various injection methods.
Brief introduction to Ninject
There are several Inversion of Control (IOC) containers for .NET to pick from such as Unity, Windsor, StructureMap and Castle. Ninject is the new Container tool in the arena, but sufficiently stable at version 2.0.
Ninject tries to focus on "simplicity and ease of use", removing features that are not deemed necessary (to the point that XML configuration is not offered out-of-the box).
Experimenting the dependency injection with Ninject
You can download Ninject from http://www.ninject.org/download.html free of cost. You might have to download the most appropriate version based on your project. I did that for testing it in our example.
You must include the Ninject.dll to your project to work with it.
Now we need to modify the class B to add the attribute [Inject] that tells the injector that the class is expecting the injector to inject the object.
public class ClassA : IClassA
{
private IClassB _classB;
[Inject]
public IClassB ClassB
{
get { return _classB; }
set
{
if (value == null) throw new ArgumentNullException("value");
_classB = value;
}
}
public void DoSomethingFromClassB()
{
_classB.DoSomething();
}
}
Now we modify our program class as in the following:
public class MyModule : NinjectModule
{
public override void Load()
{
Bind<IClassB>().To<ClassB>();
}
}
class Program
{
static void Main(string[] args)
{
IClassA classA = new ClassA();//creating instance of class A
IKernel kernel=new StandardKernel(new MyModule());
var myClass = kernel.Get<ClassA>();
//classA.ClassB = classB;
//Call the method
myClass.DoSomethingFromClassB();
Console.Read();
}
}
Observe that I have added a new class which overrides the Load method of the Ninject.Module class. In this method, we specify the binding of the IClassB to ClassB. So, any references to IClassB will be dealt with by the concrete class ClassB.
The Kernel object (Niject uses a Kernel object to provide concrete implementations of dependencies at runtime) uses StandardKernal, a default implementation of Kernel object, to load the dependencies.
IKernel kernel=new StandardKernel(new MyModule());
If you observe in the preceding code I am not setting the property of the ClassA i.e. ClassB instance, but I am asking Kernel to decide what instance of ClassA it is dependent on and asking it to return the instance. In our case, it is ClassB.
var myClass = kernel.Get<ClassA>();
The [Inject] method in the ClassA tells the Kernel that it is dependent on the IClassB type and resolves the binding by creating an instance of ClassB and provides it to the ClassA.
Note that if you remove the [Inject] attribute and if you explicitly set the property of the ClassA, the code still works.
IClassA classA = new ClassA();//creating instance of class A
IKernel kernel=new StandardKernel(new MyModule());
var classB = kernel.Get<IClassB>();
classA.ClassB = classB;
//Call the method
classA.DoSomethingFromClassB();
Console.Read();
Constructor Injector using Ninject
In this code, there is nothing much different from the previous except that we are using a constructor to inject the dependent object. In our case, the dependent object is ClassB. Ninject at runtime will check the dependencies of the classA and resolve it.
The code to accomplish it is as below:
public interface IClassA
{
void DoSomethingFromClassB();
}
public class ClassA : IClassA
{
private readonly IClassB _classB;
[Inject]
public ClassA(IClassB classB)
{
_classB = classB;
}
public void DoSomethingFromClassB()
{
_classB.DoSomething();
}
}
public class MyModule : NinjectModule
{
public override void Load()
{
Bind<IClassB>().To<ClassB>();
}
}
class Program
{
static void Main(string[] args)
{
IKernel kernel = new StandardKernel(new MyModule());
var instance = kernel.Get<ClassA>();
instance.DoSomethingFromClassB();
Console.Read();
}
}
Method Injector with Ninject
Similarly, we can inject a dependent object using Method Injector as below:
public class ClassA : IClassA
{
private IClassB _classB;
[Inject]
public void SetClassB(IClassB classB)
{
_classB = classB;
}
public void DoSomethingFromClassB()
{
_classB.DoSomething();
}
}
public class MyModule : NinjectModule
{
public override void Load()
{
Bind<IClassB>().To<ClassB>();
}
}
class Program
{
static void Main(string[] args)
{
IKernel kernel = new StandardKernel(new MyModule());
var instance = kernel.Get<ClassA>();
instance.DoSomethingFromClassB();
Console.Read();
}
}
In this article we have seen how to use Ninject to inject the dependency objects through Constructor, Setter and Method Injectors.