Skip to content

Changes in Ninject 2

bartelink edited this page Feb 26, 2012 · 15 revisions

Ninject 2 represented a ground-up rewrite of the original Ninject, created to take advantage of new language features and re-dedicate the project to obsessive minimization and simplicity.

Things that are in Ninject 2 that were not in Ninject 1.x:

  1. Cache-and-collect lifecycle management: Rather than using binding behaviors, Ninject 2 uses a scoping system and leverages the garbage collector to reclaim instances. (This is explained in detail below.)
  2. Multi-injection: The kernel in Ninject 2 now has GetAll<T>() methods, and supports injection of multiple targets with types IEnumerable<T>, List<T>, and arrays of T.
  3. Constrained resolution: Rather than just declaring conditional bindings, constraining predicates can now flow into a resolution request from the point of injection.
  4. Common Service Locator support: Because of multi-injection, Ninject 2 now has full support for the Common Service Locator.
  5. Optional modules: You can now register bindings directly on the kernel; modules are optional. If you register bindings in a module, and then unload the module, the bindings will be un-registered.
  6. Automatic module scanning: Ninject 2 can scan directories for assemblies that contain modules, and load them into the kernel.
  7. Simplified extension model: Internally, Ninject 2 relies on an inversion of control container of its own, reducing factory bloat and making extension of the core much simpler.
  8. Mono support: Ninject 2 finally has proper support for the Mono project’s version of the CLR.

Things that were in Ninject 1.x that are not in Ninject 2:

  1. Support for .NET 2.0: Since Ninject 2 relies on LINQ, .NET 2.0 support is now no longer possible.
  2. Field injection: This is a bad practice, and has been cut for minimization.
  3. Behavior attributes: Since behaviors have been cut and replaced by the new cache-and-collect system, attributes like [Singleton] no longer make sense.

Some things have been moved from the core to extensions as well, including aspect-oriented programming support (interception) and logging.

Cache-and-collect lifecycle management

The structure of instance re-use has been completely revamped in Ninject 2, which now allows any POCO to become a scoping object. This is explained in further detail on Nate’s blog. The details aren’t particularly important; all you need to know is that the syntax for defining lifecycle is a little different:

Lifecycle Ninject 1 Ninject 2
Transient Bind<A>().To<B>().Using<TransientBehavior>() Bind<A>().To<B>().InTransientScope()
Singleton Bind<A>().To<B>().Using<SingletonBehavior>() Bind<A>().To<B>().InSingletonScope()
One-Per-Thread Bind<A>().To<B>().Using<OnePerThreadBehavior>() Bind<A>().To<B>().InThreadScope()
One-Per-Request Bind<A>().To<B>().Using<OnePerRequestBehavior>() Bind<A>().To<B>().InRequestScope()

One caveat: Since this system relies on the garbage collector to deactivate and release activated instances, this can cause memory bloat in some scenarios, particularly for request-bound instances. Because of this, there is a built-in OnePerRequestModule, an HTTP module that you can load into your ASP.NET application which will deterministically collect cached instances synchronously during the teardown phase of the relevant request processing lifecycle.

Version 3 implements a more generalised version of this capability which is leveraged by custom scopes such as (in WCF where one is not integrating into the HttpContext pipeline) InScope( ()=> OperationContext.Current), i.e., any context where the OnePerRequestModule automatic HttpContext.Current-scoped cleanup will not be sufficient.**

How OnePerRequestModule is hooked in in v2.x:

v2.0

In the original v2 release, OnePerRequestModule is hooked in by the Core code in Ninject.dll automatically (this is excluded in builds with NO_WEB #defined).

v2.0

In the original v2 release, OnePerRequestModule is hooked in as long as you Kernel.Load the Ninject.Web extension.

New constructor selection semantics

  1. If a constructor has an [Inject] attribute, it is used. If multiple constructors have an [Inject] attribute, Ninject will throw a NotSupportedException.
  2. If no constructors have an [Inject] attribute, Ninject will select the one with the most parameters that Ninject has registrations for (or throw if there isn’t a single on satisfying that criteria).
  3. If no constructors are defined, Ninject will select the default public parameterless constructor.

Other API Changes

  1. IModule has been replaced with INinjectModule
  2. StandardModule has been replaced with NinjectModule
  3. There is no more InlineModule, you can bind directly against the kernel.
  4. The Ninject.Core namespace no longer exists.
  5. Get<T> calls are now implemented as extension methods.
  6. Extensions are now broken out into their own projects rather than bundled into the core.

Changes between 2.0 and 2.2

  1. If the kernel has more than one binding for a type and is being asked to inject just one (not an array) a ActivationException will be thrown. Previously the kernel would return the First:http://msdn.microsoft.com/en-us/library/system.linq.enumerable.first.aspx binding that satisfied the requirement.

Go back to the Home page or the Table of Contents

Continue reading: Why Use Ninject?