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:
- Get the name of the Class as a string
- Find the Type that has this name
- Instantiate it
- 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); }