Before I even begin to write about this topic let me clarify one thing. This is an example of the infamous Service Locator pattern or some call it an anti-pattern. There are tons of articles on the internet, and I suggest you read some of them before you begin to implement the following sample code. However, there are some occasions where using the Service Locator pattern might be your only option, possibly when dealing with some badly architected legacy code for example.
One of my requirement was that I needed to pass in constructor arguments that could only be defined at runtime. None of the search results were helpful because half of them just talked about using the “WithConstructorArgument” method of Ninject when binding my classes, which only works for arguments that can be defined at compile time, and the other half search results started preaching why I shouldn’t use the Service Locator pattern, not very useful.
You could find the complete running code at GitHub: https://github.com/tenzinkabsang/IoC_ServiceLocator
After bunch of fiddling around with Ninject code and going through the documentation I was finally able to come up with a solution. Basically, Ninject does not expose any of its binding information, more specifically the binded types, which I need in order to get information about its constructor parameters and such. So, the way I extract type information is by appending the “Bind” method with the “WithMetadata” method for any class that requires runtime arguments.
After I add the type information into the binding for any dependencies that requires runtime constructor arguments, I can use this metadata information when resolving it via the key. The following code shows my Resolve<T> method which handles both cases, with constructor arguments and without. When a type needs to be resolved, if there are no arguments passed in then it calls the simpler version of “kernel.Get<T>()” and this should be called for 90% of the request because having runtime constructor arguments should be rare. However, when arguments are passed in, it uses the metadata to get the registered type information and uses reflection to get to its constructors and constructor parameters.
And the way you use this is as follows:
In conclusion, by adding the metadata information when binding dependencies you can get the binded type information in Ninject. I guess the hard part is trying not to forget to add this extra bit of information, in which case a runtime exception will be thrown – which by the way is very descriptive.