-
Notifications
You must be signed in to change notification settings - Fork 530
Modules and the Kernel
With some dependency injection frameworks, your XML mapping files can quickly grow large and difficult to navigate. Even in some that aren’t based on XML mapping files, you still end up with a big monster service binding sequence. With Ninject, your type bindings are collected into groups called modules. Each of these modules represents an independent segment of your application. They can be organized as you see fit in order to segregate your system into subsystems in a way that makes your overall architecture easy to grow. Modules just need to implement the INinjectModule
interface, but most should extend the NinjectModule
class for simplicity.
Here’s an example:
public class WarriorModule : NinjectModule
{
public override void Load()
{
Bind<IWeapon>().To<Sword>();
Bind<Samurai>().ToSelf().InSingletonScope();
}
}
Ninject can auto-load NinjectModules if the assembly name conforms to the following pattern:
Ninject.Extensions.*.dll
Ninject.Web*.dll
Once you create modules, you load them into a container called the kernel. As the name suggests, the kernel is the core of your application. To request an instance of a type from Ninject, you call the Get()
extension method.
(A number of extension methods that can be called against the kernel are contained in the extension class Ninject.ResolutionExtensions
, if you are using Ninject;
then you’ll see the methods available to call on the kernel).
This example illustrates how to create a kernel, and activate and use an instance of the Samurai
type:
class Program
{
public static void Main()
{
IKernel kernel = new StandardKernel(new WarriorModule());
Samurai warrior = kernel.Get<Samurai>();
warrior.Attack("the evildoers");
}
}
After Ninject works its magic, the result of the call to Get()
is a Samurai
armed with a Sword
. Therefore, the call to the Samurai.Attack()
method results in the same output that we saw earlier: Chopped the evildoers clean in half. More information about the full process Ninject follows when Get()
is called is described in The Activation Process.
You can create as many modules as you’d like, and pass them all to the kernel’s constructor:
class Module1
{
public void Load() { ... }
}
class Module2
{
public void Load() { ... }
}
class Program
{
public static void Main()
{
IKernel kernel = new StandardKernel(new Module1(), new Module2(), ...);
...
}
}
Also, keep in mind that modules are executed just like any other code in your application. Nothing says they’re limited to a boring, static collection of bindings. You can always do more creative things like this:
class WeaponsModule : NinjectModule
{
private readonly bool useMeleeWeapons;
public WeaponsModule(bool useMeleeWeapons) {
this.useMeleeWeapons = useMeleeWeapons;
}
public override void Load()
{
if (this.useMeleeWeapons)
Bind<IWeapon>().To<Sword>();
else
Bind<IWeapon>().To<Shuriken>();
}
}
class Program
{
public static void Main()
{
bool useMeleeWeapons = false;
IKernel kernel = new StandardKernel(new WeaponsModule(useMeleeWeapons));
Samurai warrior = kernel.Get<Samurai>();
warrior.Attack("the evildoers");
}
}
This will result in our Samurai
being armed with a Shuriken
, causing the output Pierced the evildoers armor. If you set the useMeleeWeapons
flag to true, the binding would be from IWeapon
to Sword
, resulting in the output Chopped the evildoers clean in half. Many more advanced scenarios are possible, including reading configuration files, command-line arguments, and the like. And we still haven’t even talked about contextual bindings! :)
In case you want to load a module into several kernel instances you have to create a new instance of the module for each kernel.
The extension class Ninject.ModuleLoadExtensions
contains a number of IKernel
extension methods that instruct Ninject to dynamically find and load modules. This module location strategy is often used for plugin or Composite based architecture styles such as the Onion Architecture and allows one to decouple your container application from its slot-in subsystems.
kernel.Load("*.dll");
This call will cause Ninject to search all DLLs in the current directory and load any public INinjectModule classes it finds. The modules need to have a public parameterless constructor.
kernel.Load(AppDomain.CurrentDomain.GetAssemblies());
This method takes a list of Assembly
to load, in this example it searches all of the assemblies already loaded in the current AppDomain’s standard load context.
Continue reading: Providers, Factory Methods and the Activation Context
Licensed under Apache 2 License
Contents
- Home
- Why Use Ninject
- Getting Started
- Dependency Injection By Hand
- Dependency Injection With Ninject
- Injection Patterns
- Multi Injection
- Object Scopes
- Modules and the Kernel
- Providers, Factory Methods and the Activation Context
- The Activation Process
- How Injection Works
- Contextual Binding
- Conventions-Based Binding