Loading a Type specified in web.config, for example a Ninject Module

Yesterdays article about having your own configuration section in web.config included the option injectionModule:

<myApp injectModule="MyApp.MyAppTestNinjectModule">

The reason I am doing that is because I use Ninject 2 to do dependency injection on my ASP.net MVC 2 app.. Basically I have multiple database backends for my application and the TestNinjectModule implements an in-memory List so that I can develop the application without caring about data persistence yet.

Ninject uses so called Modules that specify the bindings. I have two modules, and my Test Module looks like this:

public class MyAppTestNinjectModule : NinjectModule
{
    public override void Load()
    {
        // As the Test Repositories usually use internal Lists, they need to be Singleton
        Bind<IProjectRepository>().To<TestProjectRepository>().InSingletonScope();
        Bind<INoteRepository>().To<TestNoteRepository>().InSingletonScope();
    }
}

So everytime Ninject sees IProjectRepository, it knows that it should give me the class TestProjectRepository. (Bonus Tip: When using List<T> as data storage, use InSingletonScope to make sure one instance is shared throughout the entire Application) My second Ninject module looks identical, except that I use MSSqlProjectRepository.

I wanted to have this configurable so that I can easily change between them or add more. Previously, creation of the Kernel (CreateKernel in global.asax) looked like this:

protected override IKernel CreateKernel()
{
    return new StandardKernel(new MyAppTestNinjectModule());
}

See that call to new MyAppTestNinjectModule()? If I want to change it, I need to recompile and redeploy the App.

The change itself is straight-forward if you know a bit of reflection. Here is what we need to do:

  1. Get the name of the Class as a string
  2. Find the Type that has this name
  3. Instantiate it
  4. Pass the instance to the StandardKernel constructor

Here is the overly commented code to do that:

protected override IKernel CreateKernel()
{
    // MyAppSettings is the class that reads the setting from
    // web.config
    string moduleName = MyAppSettings.InjectModule;

    // Type.GetType takes a string and tries to find a Type with
    // the *fully qualified name* - which includes the Namespace
    // and possibly also the Assembly if it's in another assembly
    Type moduleType = Type.GetType(moduleName);

    // If Type.GetType can't find the type, it returns Null
    NinjectModule module;
    if (moduleType != null)
    {
        // Activator.CreateInstance calls the parameterless constructor
        // of the given Type to create an instace. As this returns object
        // you need to cast it to the desired type, NinjectModule
        module = Activator.CreateInstance(moduleType) as NinjectModule;
    }
    else
    {
        // If the Type was not found, you need to handle that. You could instead
        // initialize Module through some default type, for example
        // module = new MyAppDefaultNinjectModule();
        // or error out - whatever suits your needs
        throw new MyAppConfigException(
             string.Format("Could not find Type: '{0}'", moduleName),
             "injectModule");
    }

    // As module is an instance of a NinjectModule (or derived) class, we
    // can use it to create Ninject's StandardKernel
    return new StandardKernel(module);
}