Possibility to add option for locking (or not) on first GetInstance<>/GetAllInstances<> call?

Aug 28, 2012 at 2:15 PM

This was something I came by when using the Simple Injector. For our current project we have some weird construction to get from our 'core' application to our GUI part. We control the core part, the GUI part (WPF).. but not the part what mediates between the core and GUI.

// Core part
container.RegisterSingle<IFruitManager, SomeFruitManager>();
.. more registers..

// Then we call the GUI creator (no control on this code)
GUICreator creator = new GUICreator();

// Magic stuff happens now

Somewhere in the GUICreator it comes back at our UI project. In creating (constructor) of the modules getting loaded by the GUICreator I want to register the ViewModels in the same container. Currently I get the container locked exception. And completely logically. Because the core application is continuing starting up.

Yes, I can create a UI container and a Core container.. But I want all the good stuff in the same container :) And ofcourse, everything I build is the good stuff :)

I've downloaded the source and creating this for myself, but I can understand I'm not the only one thinking this would be nice!

What I'm suggesting is to get an extra container option. To disable the locking when getting an instance. And maybe a method to force the lock ourselves.

Coordinator
Aug 28, 2012 at 3:11 PM
Edited Sep 5, 2012 at 3:41 PM

Thanks for your feedback.

Preventing any (external) changes to the container from a certain point on (the lock), is a feature that is there for both functional and technical reasons.

Functionally, in most situations it wouldn't make sense to make changes to the configuration while the application is running, since this would allow changing the configuration while the application is running. This would make the application again much more complex, while dependency injection tries to make things easier. It could easily cause very strange, hard to debug, hard to verify behavior, and would mean the application references the container, which is a big no-no. Especially when running a multi-threaded application, this could lead to very undeterministic behavior.

Instead you would usually register a proxy, to allow you to change behavior while the application is running, or you use unregistered type resolution to resolve unregistered types later on (this is what the RegisterOpenGeneric extension method does under the covers).

Since it functionally is not really great thing to do, Simple Injector forces this upon it's users. Technically, this limitation allows some very interesting features. For instance, this allows the container to work without any synchronization (in the happy path), which improves performance. However, since the container knows registrations will not change after the initialization phase, it can optimize the creation of instances. Just like the JIT does method inlining, Simple Injector does some sort of 'inlining' when building up an object graph (it prevents calling back into the container during a single object graph). Simple Injector will compile a delegate that will create the whole object graph. Replacing an existing dependency however, does not invalidate the compiled delegates, which means that the old dependency is still hanging on.

Implementing such 'unlock' feature, means that all cached delegates must be invalidated, and all caches must be cleared. However, this can have other side effects, such as clearing singletons, which means a new instance will be created. However, from the container's standpoint, there's no way of knowing, whether it is okay, to create a second instance of a type that is registered as singleton. Another option is to remove the lock-free behavior of the container, and remove the optimizations. This however, means a big drop in performance, which is not something I'm willing to do.

Although I understand this could be useful feature in some situations, I am very careful with adding such  feature, because it is hard to get right, will just ‘pollute’ the API with something usually don’t need, and it will be abused about 99% of the time; people will shoot themselves in the foot when doing this.

In your situation however, you're probably just adding new dependencies, which means that it is probably quite safe to do so, as long as your container is not yet accessible from multiple threads, and you're in the start-up path of the application. So what you could do is flip the Container.locked flag using reflection. Of course your application might break in future versions.

My gut feeling however, says that there are better ways to do this, even in your situation. Unfortunately I don't have enough information about your situation to give you any better advice about this. So if you like to take this discussion offline, be my guest. You can contact me using the CodePlex contact form.

Marked as answer by dot_NET_Junkie on 11/5/2013 at 7:34 AM
Feb 8, 2013 at 12:23 PM
Having similar problem with locking I can relate to paalders why this feature has it's uses.
I am using Caliburn.Micro with it's internal IoC responsible for creating Views for ViewModels, constructors of shell ViewModel and a Tab ViewModel are the only reasonable place to put Register calls to to satisfy dependencies on main app and tab vm interfaces like IHasManu / IHasToolbar or ISupportsTabs for example - just invented these as I am in the middle of designing a framework.

But some interfaces need to be satisfied by instances which were already dependent on other implementations and here is the hard part - either to manually create these parent objects which will pollute the bootstrapper or - if possible - do Register ->Get -> Resister -> Get ... The latter scenario is not supported by SimpleInjector.

There is one more use case I can anticipate will be a problem - dynamically loaded modules. IoC containes weren't designed to do it (MEF was), but IoC containers on the other hand are there to make the developer's life easier and help to write manageable code at the same time.
When my app will need an extra functionality later on (as application start up should be as fast as possible by any means so not loading all assemblies at once will help to reduce it's startup time),
I wouldn't be able to use IoC before all dependencies has been loaded or I would need to have another instance of IoC for the extra module, which will pollute the code base even more.
For these reasons I chose to use LightInject for WPF development (has it's own quirks as Property Injector does not handle generics well) but this can be easily fixed by commenting out or fixing some code as it consists only of a single unit. At the same time the performance is not compromised - Emit is used extensively.

Just a few thoughts, I like SimpleInjector but it just cannot "lock" the user from the non-linear workflow.