Ninject: choosing the wrong constructor

I have an ASP.NET MVC 3 application with Ninject v2.2.1.4. Everything worked fine, and then we started to see how Ninject is trying to create our DbContext using a constructor with a parameter over a constructor without parameters. Here are the bindings:

kernel.Bind<MyContext>().ToSelf().InRequestScope(); kernel.Bind<IUnitOfWork>().ToMethod(ctx => ctx.Kernel.Get<MyContext>()); kernel.Bind<DbContext>().ToMethod(ctx => ctx.Kernel.Get<MyContext>()); 

MyContext is a DbContext object that also implements the IUnitOfWork interface. I configured it so that the same context is entered into several repositories that are used in the same request. MyContext constructors look like this:

 public MyContext() { } public MyContext(string connectionString) { } public MyContext (long accountID) { } public MyContext (Connection connection) { } 

There are different constructors for different applications, since they all use the same MyContext class. Looking at the bindings that you might think when the MyContext class was requested, the constructor without parameters would be called, but for some reason this is not the case. One with the long parameter accountID is called, even if no account identifier is specified. This explicitly makes and excludes the statement that "There are no suitable bindings and the type is not self-switching." It actually throws an exception when trying to create IUnitOfWork.

If I comment on the last three constructors, everything works fine, and the constructor without parameters is used. If I comment on any two of the parameterized constructors, it tries to use the other, and not without parameters.

Suggestions offered by Ninject:

 Suggestions: 1) Ensure that you have defined a binding for long. 2) If the binding was defined in a module, ensure that the module has been loaded into the kernel. 3) Ensure you have not accidentally created more than one kernel. 4) If you are using constructor arguments, ensure that the parameter name matches the constructors parameter name. 5) If you are using automatic module loading, ensure the search path and filters are correct. 

We have nothing for 1, as we do not want it. I'm not sure what 2 and 5 mean. I don't think we made 3, and we don't 4.

Any thoughts on why the constructor without parameters would not use in this scenario.

+7
source share
2 answers

@Xander's answer is correct, but Ninject has some very specific solutions in V3. Ninject evaluates the constructors for a particular algorithm that one should find that has most of the parameters it knows how to resolve, as described in this wiki article [claims for V2.4, which was actually tagged 3.0]. See code . I think this is also on the wiki. If this is not the case, someone should put it there.

RE changes in the behavior you saw, the likelihood that Implicit Self Binding will change target points (new registrations are added at the time of resolution), or you added a binding that made one of the other constructors more attractive.

The [Inject] attribute intercepts all other criteria that you use (although in fact you do not want to have container-specific attributes in your code).

The proposed WithConstructorArgument method WithConstructorArgument actually executed using ToConstructor - WCA implementation will not affect the choice (and, I believe, you will not receive complaints about redundant specifications.

The real bottom line is that you should never end up with as much mess as mentioned by @Mark Seemann on this related question .


Unfortunately, above all this is a lie. If you upgrade from v2.2, this answer will be correct. If you cannot or do not want to, you need to look at the equivalent source and tests to find out the rules before that (from memory (and some Google code that appeared in the search results in my research), it was based on the constructor counter, but not sure that equal scores are eliminated.

It’s pretty accurate that in 2.2, adding [Inject] is a quick way out.

+5
source

By default, Ninject, along with other similar IoC structures, selects the constructor with the most parameters. Specify which constructor to use during initialization using the WithConstructorArgument extension WithConstructorArgument .

 kernel.Bind<DbContext>() .WithConstructorArgument("connectionString", ConfigurationManager.ConnectionStrings["connection"] .ConnectionString) .ToMethod(ctx => ctx.Kernel.Get<MyContext>()); 

To force Ninject to use the default constructor, put the [Inject] attribute in the constructor:

 [Inject] public MyContext() { } 
+4
source

All Articles