Ninject 3.0 release candidate has gone live. This release introduces some new feature and some changes in its behavior. This blog post will give you detailed information what has changed. It covers mainly Ninject core. Other blog posts that describe the changes and the new extensions will follow soon.
New fluent syntax to bind multiple interfaces to the same service
One of the big lacks of previous Ninject version was that there was no real support for the “Interface segregation principle”. It was not easily possible to tell Ninject that several interfaces shall be bound to the same service so that in case of a singleton the same instance is returned for different interfaces. Ninject provides now a fluent syntax that allows you to bind up to 4 interfaces together to the same instance:
Bind<IInterface1, IInterface2, IInterface3, IInterface4>().To<Implementation>(). ...;
Some may ask what is if I want to bind more than four interface to the same service. In a small discussion we came to the conclusion that if you have more than four interfaces on a single service than most likely you have a problem with the single responsibility principle and should fix this in first place. So I put the limit to four for the fluent syntax because adding additional ones means quite a bit of work in the implementation. For those that really need more interfaces there is a workaround though:
var bindingConfiguration = Bind<IInterface1, IInterface2, IInterface3, IInterface4>() .To<Implementation>() .BindingConfiguration; kernel.AddBinding(new Binding(typeof(IInterface5), bindingConfiguration)); kernel.AddBinding(new Binding(typeof(IInterface6), bindingConfiguration));
Fluent syntax changes
Several changes for the fluent syntax were introduced:
- ToConstructor has been added. See Ninject constructor selection preview for detailed information.
- WhenInjectedInto previously matched only when the target type was exactly the specified one. Now it matches also if the target is derived from the specified type.
- WhenInjectedExactlyInto has been added for all those that want the previous behavior of WhenInjectedInto.
- WhenAnyAnchestorNamed has been added. Other than WhenParentNamed it does not match only if the parent has the specified name but also if any of its ancestors has the specified name.
- OnActivation and OnDeactivation receive now the implementation type instead of the service type as instance. In case the implementation type is undefined an object is passes as instance.
- Generic overloads for OnActivation and OnDeactivation have been added that allow casting the implementation type. This is required in case the implementation type is undefined.
Constructor selection and strong typed constructor arguments
This release introduces the new “To” fluent syntax overload “ToConstructor”. This overload allows you to select the constructor that shall be used in the fluent syntax and to specify constructor arguments strongly typed and without magic strings. For more information about this feature please read my previous blog post about this topic. Ninject constructor selection preview
Furthermore, the default selection of the constructor has been changed. Previous versions of Ninject considered constructors that have self bindable dependencies (e.g. a none abstract class) or dependencies for which a default value (int x = 3) is defined but no binding has been defined for those dependencies as invalid constructors and preferred all other constructors. In 3.0 these kinds of parameters are now treated the same way as if a binding exists for them. This can result in a different behavior of your application in case you have more than one constructor for your classes.
This version also requires that the constructor is uniquely selected. In case there is more than one constructor available with the same weight an activation exception is thrown. In this case you have to select the constructor manually (e.g. by using the new ToConstructor syntax).
Entity Framework
The change of the constructor selection changes the behavior of the Entity Framework. The entity framework adds several constructors to the ObjectContext. You have to select the parameterless constructor explicitly. E.g. by adding the following binding:
this.Bind<MyEntities>().ToConstructor(x => new MyEntities());
Inherited constructor arguments
Previously it was possible to pass constructor arguments to the resolved object by passing ConstructorArgument to “Get”. This feature was extended so that it is now possible to pass the constructor arguments to deeper levels too using the following syntax:
kernel.Get<IFoo>(new ConstructorArgument("parameterName", value, true)); kernel.Get<IFoo>(new ConstructorArgument("parameterName", context => LazyEvaluatedValue(context), true));
Changed to client profile and removed InRequestScope
Version 3.0 is now build as client profile library. Since InRequestScope requires a reference to System.Web it was removed from Ninject core. This scope type is now provided by the new Ninject.Web.Common extension which is the base for all web type extensions.
Various small changes
- Support for constructor parameter with a default value has been added. If a constructor parameter has a default value it is used in case there is no explicit binding defined.
- Services that are bound using ToConstant are now in singleton scope by default. This decreases the work required when it is used somewhere.
- Open Generics bindings are now overridable by a closed generic binding of the same generic type.
- Instead of specially handling IKernel internal a default binding for IKernel and IResolutionRoot is added by the kernel during construction. This makes it possible to Rebind them if required.
Small extension changes
- Ninject.Extensions.ContextPreservation: BindInterfaceToBinding has been removed. Use the new Ninject core syntax to bind multiple interfaces to one implementation instead.
- Ninject.Extensions.Xml: InRequestScope requires the additional extension Ninject.Web.Common.Xml.
FYI this post does not appear in the archives – neither category, tag or author. If I wasn’t subscribed to you I wouldn’t have seen it. Of course, could just be me…
Remo, based on your post at http://stackoverflow.com/questions/9792237/how-to-properly-configure-ninject-extensions-logging-log4net-in-my-mvc3-project and your comment at https://github.com/ninject/ninject.extensions.logging/issues/8, I installed the RC of of ninject 3.0.0-rc3. However, my project doesn’t build now. I am using Ninject.MVC3 and Ninject.Extensions.Convensions and I tried updating both of which to the -Pre release for v.3 through the Package Manager Console. That didn’t fix the issue though. The errors are in the my NinjectMVC3.cs file (which was created with the non-pre release of Ninject 2). The errors are that the OnePerRequestModule and HttpApplicationInitializationModule could not be found, and then when I try to use the “Scan” method from the conventions extension… it fails on “kernel.Scan(x => { x.FromAssembliesMatching(“*”); x.BindWith(); });”. Any assistance you can provide on the upgrade path to these “-pre” components?
@Brian
Please read the Upgrade section in the Ninject.MVC3 documentation:
https://github.com/ninject/ninject.web.mvc/wiki/Setting-up-an-MVC3-application
The old convention extension was replaced by a much more powerful one:
https://github.com/ninject/ninject.extensions.conventions/wiki/Configure-components-using-conventions
Thanks Remo. I’m close, but still have one last issue. With the v3 of the conventions extension, I can’t seem to figure out the equivalent of:
kernel.Scan(x => { x.FromAssembliesMatching(ā*ā); x.BindWith(); });
The code above worked with the v2 of the conventions, but v3 doesn’t contain “BindWith”. I tried the following, but it didn’t work.
kernel.Bind(x => x.FromAssembliesMatching(“*”).SelectAllClasses().BindToAllInterfaces());
Basically, I just want it so that if I have an interface named ISomeClass that it automatically binds to SomeClass. Can you help?
Clarification on the above post since the angle brackets didn’t copy correctly, here’s the v2 code that worked, replacing the angle brackets with square brackets. I need the equivalent syntax in v3.
kernel.Scan(x => { x.FromAssembliesMatching(“*”); x.BindWith[DefaultBindingGenerator](); });
@Brian
FYI – The reason I state that my v3 code doesn’t work is that in the Start method of NinjectWebCommon.cs, an error is thrown at run-time at “bootstrapper.Initialize(CreateKernel);” stating “Sequence Contains No Elements”
Remo,
If you get a chance, I posted this question and all relevant code at http://stackoverflow.com/questions/9824863/convention-based-dependency-injection-with-ninject-3-0-0. Can you look at that, and then you can delete the 3 above posts. I appreciate it!