HowTo – NInject – Part 1 – Basics

Source Code

All source code can be found on GitHub here.

My cheat sheet for NInject can be found here.

This is part of my HowTo in .NET seriies. An overview can be seen here,

This post is  a two part post on NInject:

  1. Basics
  2. Advanced Features

Intro

NInject is a dependency injection (DI) framework or inversion of control (IOC) framework.

In it’s simplest form it allows a way to register or ‘Bind’ a class which implements an interface against the interface and to resolve when required.

The Basics

The first requirement is a kernel.

IKernel aKernel = new StandardKernel();

We then bind an interface to a class.

aKernel.Bind<IClass>().To(AClass);

When we want an instance of IClass or AClass we ask the kernel for an instance of IClass.

AClass aClass = aKernel.Get<AClass>();

Classes are automatically bound to themselves. We can ask for an instance of them without binding to them.

BClass aClass = aKernel.Get<BClass>();

Resolvable and Non-Resolvable Classes

In the example above our class is presumed to have a parameterless constructor. NInject can actually resolve any constructor where all the parameters are resolvable.

A resolvable parameter is an entity which has a parameterless constructor or contains parameters which can all be resolved. This ruleset is cascaded all the way down the ‘call stack’ as far as required until there are no more parameters to resolve.

An interface parameter is resolvable if it has a binding.

A resolvable parameter can take on other forms; for example we can explicitly provide the parameters during bind time or resolve time.

Multiple Resolvable Constructors

When multiple resolvable constructors exists, the following ‘pecking’ order is used:

User defined constructor marked with [Inject] attribute
The constructor with the most known bound parameters.
The default parameterless constructor

Property & Method Injection

NInject will also inject properties and methods after an instance has been resolved. Methods and properties marked with the [Inject] attribute will all be called with any required parameters resolved.

[Inject]
public void InjectionMethod( KnownC c )
{
}

[Inject]
public KnownC InjectionProperty
{
}

Here an instance of KnownC will be injected into InjectionMethod and also InjectionProperty automatically before the kernel provides us with an instance of our resolved class.

Nested Resolves

Our cascade approach to resolving parameters also applies to Property and Method Injection.

In the example below our class Outter is resolved with an Instance of Middle injected into the property and constructor. Both instances of Middle is injected with Inner injected into both the Property and Constructor.

public class Outter
{
	[Inject]
	public Middle PropertyInject{ get; set; }

	public Middle ConstructorArgInject { get; set; }

	public Outter (Middle middle)
	{
		ConstructorArgInject = middle;
	}
}

public class Middle
{
	[Inject]
	public Inner PropertyInject{ get; set; }

	public Inner ConstructorArgInject { get; set; }

	public Middle (Inner middle)
	{
		ConstructorArgInject = middle;
	}
}

public class Inner
{
}

Constructor Arguments At Bind Time

We can provide parameters to constructor arguments at bind time. Parameters which are and are not resolvable can be provided. This is done with the WithConstructorArgument method and providing the name of the parameter ( which is case sensitive ) and also the value of the parameter to take.


var anKnownE = new KnownE ();

var kernel = new StandardKernel ();
kernel.Bind ()
	.ToSelf ()
		.WithConstructorArgument ("anInt", 1)
		.WithConstructorArgument ("aString", "Hello")
		.WithConstructorArgument ("aClass", anKnownE);

var aClass = kernel.Get ();

Constructor Arguments At Resolve Time

We can provide parameters to constructor arguments at resolve time. Parameters which are resolvable and also not resolvable can be provided. This is done by passing in an array of ConstructorArgument’s into the kernel’s Get method. The ConstructorArgument takes two parameters; the name of the parameter of our constructor parameter being resolved to and also the value; the parameter name is a string and is case sensitive.

var kernel = new StandardKernel ();
kernel.Bind ()
	.ToSelf ();

var aClass = kernel.Get (
	new [] {
	new ConstructorArgument ("anInt", 1),
	new ConstructorArgument ("aString", "Foo"),
	new ConstructorArgument ("aClass", new KnownD ())
}
);

Binding Scope

Binding scope allows determination of when a new instance of a class is provided and when an existing instance is provided.

InTransientScope: Will make the kernel always create a new instance when a class is resolved. This is the default action.

InSingletonScope: Only one instance is created per kernel instance. When subsequent resolves are made the existing instance, which was cached, is returned.

InRequestScope: Only one instance is created per kernel instance per web request instance.

InScope(Func): Provides a custom delegate to provide logic as to when a new instance is required or where the last instantiated instance is returned.

kernel.Bind().To<b>(ClassA).InTransientScope();
kernel.Bind().To<b>(ClassA).InSingletonScope();
kernel.Bind().To<b>(ClassA).InThreadScope();
kernel.Bind().To<b>(ClassA).InRequestScope();
kernel.Bind().To<b>(ClassA).InScope(x => DateTime.Now.day != x.DateCreated.day);

Kernel Modules

Kernel Modules provide a way of grouping and reusing binding registrations.

To create a kernel module inherit NinjectModule and place binding logic in Load().

OnLoad and OnUnLoad provide triggers for when a kernel module is unloaded from the kernel.

public class WarriorModule : NinjectModule
{
	// Binding code goes in here
	public override void Load()
	{
		Bind().ToSelf();

	}
	public override void OnLoad() { }   // OnLoad event
	public override void OnUnLoad() { } // OnUnload event
}

Kernel Modules can be passed into a kernel upon creation.

IKernel kernel = new StandardKernel(new AKernelModule());
IKernel kernel = new StandardKernel(new Module1(), new Module2(), ...);

NInject can use reflection to automatically load all kernel modules in a dll.

kernel.Load/UnLoad("*.dll"); // Load / Unload all Kernel Modules within dll

NInject can use reflection to automatically load all kernel modules in all dlls to be found within the current dlls domain.

kernel.Load.UnLoad(AppDomain.CurrentDomain.GetAssemblies());

Multiple Resoles

Where multiple classes are bound to the same interface, it is possible to resolve all of them in one hit.

var classes = kernel.GetAll();

These can also be injected in as an enumerable.

public AClass( IEnumerable classes)
{
}

Activation and Deactivation Trigger

We can register a delegate to be called when a resolved class is instantiated and disposed.

Bind().To<Class( ).OnActivation( x => x.ActivationMethod();
Bind().To<Class( ).OnDeactivation(x => x.DeactivationMethod());

Advanced Features

This concludes NInject Basics. More advanced features can be found here.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s