Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Error "More than one matching bindings are available" when using Ninject.Web.Mvc 2.0 and ASP.NET MVC 1.0

Recently I've switched to Ninject 2.0 release and started getting the following error:

Error occured: Error activating SomeController
More than one matching bindings are available.
Activation path:
  1) Request for SomeController

Suggestions:
  1) Ensure that you have defined a binding for SomeController only once.

However, I'm unable to find certain reproduction path. Sometimes it occurs, sometimes it does not. I'm using NinjectHttpApplication for automatic controllers injection. Controllers are defined in separate assembly:

public class App : NinjectHttpApplication
{
    protected override IKernel CreateKernel()
    {
        INinjectModule[] modules = new INinjectModule[] {
            new MiscModule(),
            new ProvidersModule(),
            new RepositoryModule(),
            new ServiceModule()
        };

        return new StandardKernel(modules);
    }

    protected override void OnApplicationStarted()
    {
        RegisterRoutes(RouteTable.Routes);
        RegisterAllControllersIn("Sample.Mvc");
        base.OnApplicationStarted();
    }

    /* ............. */

}

Maybe someone is familiar with this error.

Any advice?

like image 773
Denis Parchenko Avatar asked Mar 11 '10 09:03

Denis Parchenko


4 Answers

I finally figured this issue out recently. Apparently, the NinjectHttpApplication.RegisterAllControllersIn() function doesn't do all of the proper bindings needed. It binds your concrete controller implementations to IController requests. For example, if you have a controller class called SampleMvcController, which inherits from System.Web.Mvc.Controller. It would do the following named binding during application start:

kernel.Bind<IController>().To(SampleMvcController).InTransientScope().Named("SampleMvc"); 

But when debugging the NinjectControllerFactory, I find that request are being made for the Ninject Kernel to return an object for the class "SampleMvcController", not for a concrete implementation of IController, using the named binding of "SampleMvc".

Because of this, when the first web request that involves the SampleMvcController is made, it creates a binding of SampleMvcController to itself. This is not thread safe though. So if you have several web requests being made at once, the bindings can potentially happen more than once, and now you are left with this error for having multiple bindings for the SampleMvcController.

You can verify this by quickly refreshing an MVC URL, right after causing your web application to restart.

The fix:

The simplest way to fix this issue is to create a new NinjectModule for your controller bindings, and to load this module during application start. Within this module, you self bind each of your defined controllers, like so:

class ControllerModule : StandardModule {       public override Load() {         Bind<SampleMvcController>().ToSelf();         Bind<AnotherMvcController>().ToSelf();       }     } 

But if you don't mind changing the Ninject source code, you can modify the RegisterAllControllersIn() function to self bind each controller it comes across.

like image 197
Aaron Ramirez Avatar answered Oct 01 '22 18:10

Aaron Ramirez


I have been dealing with this problem for months. I tried so many options but was unable to come to a solution. I knew that it was a threading problem because it would only occur when there was a heavy load on my site. Just recently a bug was reported and fixed in the ninject source code that solves this problem.

Here is a reference to the issue. It was fixed in build 2.1.0.70 of the Ninject source. The key change was in KernelBase.cs by removing the line

context.Plan = planner.GetPlan(service); 

and replacing it with

lock (planner) {     context.Plan = planner.GetPlan(service); } 

To use this new build with MVC you will need to get the latest build of Ninject then get the latest build of ninject.web.mvc. Build ninject.web.mvc with the new Ninject build.

I have been using this new build for about a week with a heavy load and no problems. That is the longest it has gone without a problem so I would consider this to be a solution.

like image 23
Steven Hook Avatar answered Oct 01 '22 17:10

Steven Hook


Are you sure you really are creating a single completely new Kernel from scratch in your OnApplicationStarted every time it's invoked ? If you're not and you're actually creating it once but potentially running the registration bit twice. Remember that you're not guaranteed to only ever have one App class instantiated ever within a given AppDomain.

like image 24
Ruben Bartelink Avatar answered Oct 01 '22 17:10

Ruben Bartelink


My answer was a bit more obvious.

I had declared the binding for one of my controllers more than once during refactor of my code.

like image 24
msteel9999 Avatar answered Oct 01 '22 17:10

msteel9999