As I’ve mentioned before, while developing Ninject 2, I applied an obsessive minimization process to the development. Ninject 2 was largely a rewrite of Ninject 1, but using most of the same concepts – just re-written as necessary to be as small as absolutely possible. This minimization, along with leveraging stuff like LINQ and lambdas, has resulted in a very sleek and compact distribution, currently hovering around 82KB when compiled for release.
However, it’s also meant that I’ve had to cut features from the core, which in turn means that extensions are now of the utmost importance in Ninject 2. I’d like to adopt a model similar to the one used in jQuery, in that I handle development and maintenance of the core, and outsource the development of extensions to the community. This means if you have an idea for a cool extension to Ninject, you’ll just be able to write it, and publish it to the Ninject website (eventually).
This also means that I’m toying with different ideas for discovering and loading extensions when you spin up the kernel. I’ve tried a few things but keep gravitating towards an automatic extension loading solution, in which Ninject looks at all of the DLLs in the directory you have the Ninject.dll in for assemblies that have a NinjectExtensionAttribute. Because of the lack of raw metadata reading in the CLI, this also means that Ninject has to spin up a separate AppDomain to scan the DLLs without loading everything into the primary AppDomain.
My main concern is that this might be too magical or “heavy” for Ninject. One obvious possibility is to create an option that will control automatic extension loading, which is used like this:
var settings = new NinjectSettings { LoadExtensions = true };
var kernel = new StandardKernel(settings, ...);
So all in all I pose two questions to you, dear reader:
- Is automatic extension loading too magical, or too heavy for Ninject?
- If it’s controlled by an option, should the default be on or off? That is, should you opt-in to or opt-out of extensions?
This and any other feedback, as always, is greatly appreciated.
Related posts:











Email
Twitter
LinkedIn
Facebook
{ 20 comments… read them below or add one }
Make it explicit, default to off. Magical moments cause those half-day-wtf-then-aha moments. If people want the functionality on by default, it’s pretty easy to wrap calls to the settings in their own method.
I think extensions should be opt-in.
Spinning up an AppDomain to scan assemblies seems heavy-weight, but if it’s opt-in then at least you don’t pay that cost by default.
I’m not advocating this approach, but in the spirit of using the simplest thing that works, you could require extension DLLs to follow a particular naming scheme: “Ninject.Extension.Foo.dll”
@Brannon: Actually, that’s not a bad idea. I like the simplicity a lot, and it’s something that can be handled entirely via the filesystem without looking at the assembly metadata. Let me think about the downsides…
I like the Brannon’s idea. Althru I wouldn’t use a fixed naming schema. Why not use Ninject.Extension.*.dll as a default wildcard and allow it to be changed to something else as part of NinjectSettings.
Maybe this settings should be a IEnumerable to allow both ‘out-of-the-box’ extension from Ninject and custom extension. I don’t like mixing standard and custom code into one namespace.
On the other hand to keep Ninject light weight, shouldn’t be the extension scanner be a extension itself? If so, it settings should not be in NinjectSettings. A modular dependency injection framework has a nice ring, doesn’t it? ;-)
There’s the unmanaged Metadata API for the CLR: http://msdn.microsoft.com/en-us/library/ms404434.aspx
That said, how do you know what assemblies to scan? Where do you draw the line? The app folder and any of its subfolders? What if I’ve placed my extention in the GAC – you can’t really scan all the assemblies in there no matter the approach you choose…
I’ve used tools with similar solutions before and there are always issues – orphan files (ie stuff which was removed from the build but is still hanging around the filesystem), naming convention conflicts (ie stylecop/fxcop/whatever gets all anal about the assembly name or something), etc.
Might be better to get the best of both worlds by having a default naming scheme but also a config setting to override it (either with a different naming convention or an explicit list of extensions)
Having a config also enables changing extension sets based on build type, environment, etc.
Personally, I’d think the best option would be to spin the loading out into a interface (or abstract class) that can be specified when creating a kernel, and define two implementations in the core:
1) does the specified magic loading (perhaps with the option to scan just things already loaded in the current AppDomain)
2) one where you specify exactly which extensions to be loaded into the kernel.
It should default to null, which would load no extensions.
I like the idea of the extensions being auto-loaded but only if explicitly asked to do so. If possible the location(s) to search for extensions should be configurable. I do something similar in one of my projects but rather than use an attribute I look for those types implemeting a specific interface.
I have a couple of thoughts here.
First off, is it worth using MEF or possibly the Addins framework rather than writing Yet Another Plugin Architecture?
Secondly, I think this might be too heavy to include in the base assembly. Could you move module loading to another assembly? Have a special type of Kernel that subclasses StandardKernel, say ModularKernel, that handles loading of extensions.
I think that maybe spinning a new appdomain just for loading is a bit too much. Also I think that this won’t be allowed in Medium Trust (we had the same problem with Subtext plugin API).
We ended up specifying which plugin to load inside the app.config file, but I know you build Ninject to avoid that kind of situation :)
But think about it: in that case you will not be using the app.config to configure the container, but just to load extension plugins that augment the functionality of the container. So, hopefully, they won’t be too much, and won’t change as often as the container configuration changes.
But, what kind of extensions are you thinking about?
I mean, modules are already a kind of extensions: you can just write your own module and pass it to the kernel. What other scenario are you thinking about?
Actually, I like the idea of being able to specify a loading strategy. You can include a default strategy that is filesystem-based. The opt-in would be passing an instance of the strategy to the kernel. That would also allow people to create their own strategies if necessary.
One things for sure, you won’t be able to please us all! :P
I would vote for a mechanism that is simple and operates in medium trust environments — of course “simple” is subjective to some extent, but medium trust is not.
I don’t think there’s anything wrong with specifying a naming convention for assemblies — and providing the ability to override that pattern in the kernel settings. I think that provides you a mechanism for easy assembly identification and eliminates the need for spinning up a separate app domain. And, yes, it places some responsibility back on the developer to not screw up and RTFM (or wiki page or whatever the case may be), but what’s wrong with that?
I like the extension loading idea, but not turned on by default. I’d opt for a solution where an ExtensionDiscovery strategy class is passed to ninject to load extensions.
Possible ExtensionDiscovery strategy implementations could be:
* NoExtensionDiscovery
* AssemblyExtensionDiscovery
* AutoExtensionDiscovery
with NoExtensionDiscovery as default.
IExtensionDiscovery interface would have a method GetExtensionTypes with a signature somehow like this:
IExtension[] GetExtensionTypes()
{
…
}
Code could look like this:
var settings = new NinjectSettings { ExtensionDiscovery = new AssemblyExtensionDiscovery().ByType().ByType() };
var kernel = new StandardKernel(settings, …);
Could be nice, no selector argument needed, extensible as such too.
This is just a thought…what if you made the extension loading mechanism an extension itself? And require the user to load it if they want to use it.
Looks like Christoph had the same idea as me kind of.
Is Ninject 2.0 development dead?
@Adriano: Nope, it just hasn’t needed much attention lately. :) Full release will be coming soon.
5 Months later – same question: Is it dead? :)
Same question from over here.. Is Ninject dead?
We are just evaluating this framework and really like what we see but are hesitant about picking up a dying technology.. any news?
And one more of the same… Is Ninject dead and if not is there an expected release data for version 2?