2

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);
        }                           
    }
Bearington
  • 102
  • 2
  • 9

1 Answers1

2

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);
BatteryBackupUnit
  • 12,934
  • 1
  • 42
  • 68
  • Thankyou for your response i had a feeling i would need to restructure how i did things. I don't really want to have to hard code anything so i might refactor the code so the modules return something i can parse before loading the bindings so that i don't get any duplicates. – Bearington May 22 '14 at 15:58