Skip to content

Changes in Ninject 2

nkohari edited this page Sep 13, 2010 · 15 revisions

Ninject 2 represents 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, we also supply a OnePerRequestModule, an HTTP module that you can load into your ASP.NET application which will more aggressively collect cached instances when each HTTP request ends.

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 understands how to resolve.
  3. If no constructors are defined, Ninject will select the default parameterless constructor.