Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ninject Error with multiple bindings

I have an MVC4 app that uses reflection to load controllers at run time. These controllers as well as the main app use Ninject to inject things into the constructors.

Each dynamic controller maintains a list of all the bindings it needs and stores them as a Ninject module that the main app loads at run time.

I'm having issues at the moment where multiple dynamic controllers contain the same bindings. I want the dynamic controllers to be self contained so i don't want to remove the bindings from inside the controller projects and i don't really want to have to parse a txt or xml document to read all the bindings.

Is there a way to remove duplicate bindings or tell Ninject to use the first binding it comes across if there is more than one.

Loading all the referenced assmblies bindings

public static StandardKernel LoadNinjectKernel(IEnumerable<Assembly> assemblies)
{
    var kernel = new StandardKernel();

    foreach (var asm in assemblies)
    {
       asm
       .GetTypes()
       .Where(t =>
              t.GetInterfaces()
                   .Any(i =>
                       i.Name == typeof(INinjectBootstrapper).Name))
            .ToList()
            .ForEach(t =>
            {
                var ninjectModuleBootstrapper =
                    (INinjectBootstrapper)Activator.CreateInstance(t);


                kernel.Load(ninjectModuleBootstrapper.GetModules());
            });
    }

    return kernel;
}

Binding Class

public class NinjectBindings : Ninject.Modules.NinjectModule
{
    public override void Load()
    {
        Bind<IDMSService>().To<DMSService>();
        Bind<ICaseManagerRepo>().To<CaseManagerRepo>();
    }
}

Controller Factory

 protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType)
    {
        if (controllerType != null)
        {                
            return (IController)kernel.Get(controllerType);
        }
        else
        {               
            return base.GetControllerInstance(requestContext, controllerType);
        }                           
    }
like image 758
Bearington Avatar asked Apr 29 '26 08:04

Bearington


1 Answers

No, there is not.

You could try and see if using IBindingRoot.Rebind instead of Bind suits your need. However i would strongly advise against it, since it does not work with:

  • Multi-Binding
  • Conditional Binding when the condition changes
  • adding arguments, OnActivation/OnDeactivation,.. to the binding when they change
  • It is not thread safe

And even if you get it to work, when you have any conditions, arguments, OnActivation/OnDeactivation, you'll end up with a lot of code duplication and issues which are hard to pinpoint (whether stuff works will depend on module loading sequence). It's really not the way to go.

Instead, you can do what one always does: Eliminate duplication. Move bindings which you need at multiple places to their own module. Create some type (lets call it ControllerModules) which specifies which modules are needed for one controller. Instead of loading all modules, find all ControllerModules, read the modules from them, and load all of these modules.

In pseudo code this could look like:

IEnumerable<Type> modulesToLoad = Assemblies.InPath(...)
          .SelectAllClasses()
          .InheritingFrom<ControllerModules>
          .SelectMany(x => x.RequiredModules)
          .Distinct();
IKernel.Load(modulesToLoad);
like image 146
BatteryBackupUnit Avatar answered May 02 '26 04:05

BatteryBackupUnit



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!