16

I have couple of class libraries in my project and all are using Ninject IoC container. I wanted to load all the modules in a StandardKernel at one go wherever an INinjectModule is found. So I used:

var kernel = new StandardKernel();
kernel.Load(AppDomain.CurrentDomain.GetAssemblies())

But this doesn't work for some reason. Can anyone help?

  • Not sure you can do that in one line. http://stackoverflow.com/questions/1694640/can-ninject-load-modules-assemblies-on-demand – Jason Evans Oct 26 '11 at 13:52
  • Please check what AppDomain.CurrentDomain.GetAssemblies() is returning, maybe the assemblies you are looking for hasn't been loaded yet? – tpeczek Oct 26 '11 at 13:54
  • @tpeczek I have checked. All my assemblies are in the `List` along with the System assembles –  Oct 26 '11 at 13:56
  • @JasonEvans I tried it, but it didn't help either :( –  Oct 26 '11 at 13:56
  • @DelwarKhondokar In that case I can only ask you to check if your modules are public non abstract classes with public parameterless constructor. – tpeczek Oct 26 '11 at 14:18
  • How do you load the other assemblies? – Remo Gloor Oct 26 '11 at 14:29
  • @tpeczek its just another simple public class implemented from `INinjectModule` and written everything in the parameter-less constructor. –  Oct 26 '11 at 14:31
  • @RemoGloor I am not loading any assemblies, just the assemblies loaded along with the main program which are referenced. –  Oct 26 '11 at 14:33
  • In my case, since project was loosely coupled, a dll containing ninject module was not referrenced by main project so this dll was not in main project bin folder. after I changed output path kernel.Load("projectName.dll"); worked. – Reza Abolfathi Jun 11 '15 at 12:17

4 Answers4

22

Well, this often happens when bindings are declared but other modules are loaded where that module tries to resolve a binding which has not loaded yet. This happens because List<INinjectModule> may not in the right order.

If you think this is the case. Follow this resolution.

The idea is we will have a bootstapper for each assembly, where the bootstrapper will be responsible to load the modules in its logical order.

Let us consider an interface for bootstrapper (this we will use to find the bootstrapper in an assembly)

public interface INinjectModuleBootstrapper
{
    IList<INinjectModule> GetModules();
}

Now consider for your DataAccess assembly, implement the INinjectModuleBootstrapper:

public class DataAccessBootstrapper : INinjectModuleBootstrapper
{
    public IList<INinjectModule> GetModules()
    {
        //this is where you will be considering priority of your modules.
        return new List<INinjectModule>()
                   {
                       new DataObjectModule(),
                       new RepositoryModule(),
                       new DbConnectionModule()
                   };
        //RepositoryModule cannot be loaded until DataObjectModule is loaded
        //as it is depended on DataObjectModule and DbConnectionModule has
        //dependency on RepositoryModule
    }
}

This is how you defne the Bootstrapper for all your assembly. Now, from your program startup, we need the StandardKernel where all the modules are loaded. We will write something like this:

var assemblies = AppDomain.CurrentDomain.GetAssemblies();
return BootstrapHelper.LoadNinjectKernel(assemblies);

And our BootstrapperHelper class is:

public static class BootstrapHelper
{
    public static StandardKernel LoadNinjectKernel(IEnumerable<Assembly> assemblies)
    {
        var standardKernel = new StandardKernel();
        foreach (var assembly in assemblies)
        {
            assembly
                .GetTypes()
                .Where(t =>
                       t.GetInterfaces()
                           .Any(i =>
                                i.Name == typeof(INinjectModuleBootstrapper).Name))
                .ToList()
                .ForEach(t =>
                             {
                                 var ninjectModuleBootstrapper =
                                     (INinjectModuleBootstrapper)Activator.CreateInstance(t);

                                 standardKernel.Load(ninjectModuleBootstrapper.GetModules());
                             });
        }
        return standardKernel;
    }
}
casperOne
  • 73,706
  • 19
  • 184
  • 253
Abdul Munim
  • 18,869
  • 8
  • 52
  • 61
  • 1
    Wonderful answer! However, after searching for a while why on the Application_Start of Global.asax not all my assemblies was called, I found this interesting thread: http://stackoverflow.com/questions/18656821/why-does-appdomain-currentdomain-getassemblies-not-return-dependant-assemblies. Instead of using AppDomain.CurrentDomain.GetAssemblies(), call var assemblies = BuildManager.GetReferencedAssemblies(); – Samuel Jun 30 '15 at 19:36
4

Another thing you should check is if the class that extends NinjectModule is public, otherwise it wont be visible in the Assembly.

Zé Carlos
  • 3,627
  • 5
  • 43
  • 51
0

I think that is not a good idea to use CurrentDomain.GetAllAssemblies() because not all project assemblies can be loaded on program startup ( some assemblies can be loaded on user actions for example or other events). In this case you will have null-reference exceptions for dependencies.

Mihail
  • 11
  • 2
0

You can use reflection to find and instantiate the Ninject modules:

BuildManager.GetReferencedAssemblies()
    .Cast<Assembly>()
    .SelectMany(a => a.DefinedTypes)
    .Where(t => typeof(INinjectModule).IsAssignableFrom(t))
    .Select(t => (INinjectModule)Activator.CreateInstance(t))
Matt H
  • 7,311
  • 5
  • 45
  • 54