Common IoC denominator for Autofac, Castle and Unity .NET Containers
What's the common denominator for the Autofac, Castle, Unity and other popular .NET containers?
Some think, that it is the CommonServiceLocator - an interface that will allow library developers to abstract from the specific Container or Service Locator implementation.
At the moment of writing this contract is being supported by: Autofac, Castle, Spring.NET, Unity and StructureMap.
And I've just written Autofac Adapter for the CommonServiceLocator, just to play with the concept.
It works... but I didn't like the big picture behind.
Personally I believe that the libraries should have no logical dependencies on the container or locator at all, since having such a dependency already creates logical leak of control.
This type of control over the infrastructure should belong only to the entry modules that bind and configure everything (SoC principle - let the configuration code do the wiring). Every component and service will just live in this wired Matrix, simply leveraging what has been handed over to them and taking that for the granted.
If you need some name-based resolution (i.e. workflows or policies) inside your components or services - leverage the simple IProvider or INamedProvider interface from your common lib (it would be nice to have the first one in BCL). Such interfaces keep logical leaks at bay and they do not care if you have IDictionary, IContainer or one-line lambda resolver behind (BTW, do you see the testability here?)
Only if you really must have some static entry point into the IoC (i.e.: stateless services that are being created by some infrastructure outside of our control), then it is reasonable to resort to some IResolver interface there (still strongly-typed) that is being returned by a common static class. But this already is the wiring domain.
PS: Needless to say that the lowest common denominator is the smallest value, anyway.
Update: there is also clarification on my position towards CSL and roll-up of the proposed alternative interfaces.
Sunday, October 12, 2008 at 13:21
Reader Comments (6)
>> leak of control
I'd never thought of it that way - great little coinage.
You beat me to publishing :) One thing to note, you don't have to catch exceptions in your implementation of DoGetInstance and DoGetAllInstances. The base class does that for you.
Also, why not implement the interface? It is actually a fairly nice 1 to 1 mapping to Autofac out of the box. I did that with mine - post only to the mailing list - http://groups.google.com/group/autofac/browse_thread/thread/e7764652a5aad44a#
As I've said to others, I think that people are making two errors in their judgment of the common service locator interfaces. The first of these is to conflate dependency injection with service locator. The two go rather nicely but are quite distinct. The second, and fundamentally more important, is to assume that having a common service locator interface is some kind of encouragement to create all sorts of dependencies on it all over the place.
There are places where DI can't go. There are some places where you specifically need service location at runtime. There are points in time between there being no DI in a solution to it being everywhere in a solution. In cases like these, a service locator is key. And when one is needed, especially for the cases where it can never go away (name-based resolution, for example), we might as well have a common set of interfaces we can work against.
Arguing against IServiceLocator is like arguing against IEnumerable. Yeah, the compiler supports duck type enumerables, and we could each build our own, but a common interface is an undeniably good thing.
I just wish all you guys would stop reading so darn far between the lines! You're inventing intent where there is none.
Justin,
Damn, I should've read the groups instead of firing up VS and rushing in with the code))
Thank you for pointing out the exception thing. I'll update the code. Hm... and this, probably, is the thing that could be added to the original ServiceLocator test suite as well (making sure that the AE is not thrown by the override methods).
BTW, you've got an interesting approach on the GetAllInstances. It does not require explicit collection registrations and thus is simpler to use. But don't you need to iterate through the parent containers as well?
Regarding not implementing the interface directly - I'm just sticking to the "Keep it simple" principle))
Best regards
Jeremy,
Thank you for the comment. Answer to it has unfolded into a post of its own. It is the next one.
What do you think?
Best regards,
Rinat Abdullin
[...] my previous post on Common Service Locator I do not argue against the presence of the common interface at all. The [...]