In my post, Watch your Composition Root, I explore how to empower plugins to be apart of the application bootstrap process. After sharing this two friends of mine, Rob Earlam and Sean Holmesby supplied some feedback. Rob felt I should expand on the why of plugins and Sean made a very good point about taking dependencies on IoC frameworks in application code. Having addressed Rob's comments in a previous post, its Sean's turn.
There seem to be mixed feelings about the Composition Root. Here's another take on setting up something with Sitecore Habitat (where each module needs to be responsible for it's registrations). He says that the other way (which is similar to your approach) requires each module to have explicit references to the IoC Container DLL.... i.e adding Simple Injector to each module's project. Whereas his way, you just put them all into a collection, and get your IoC container to register them all in one place (the composition root) at the end of the pipeline.
I am a Simple Injector Fan boy, I love how opinionated and well thought out it is. The documentation is amazing and almost every question about simple injector on stack-overflow is answered (in great detail) by its creator dotnetjunkie.
To begin to work out how we might address the concerns of taking a dependency on an IoC framework from within a plugin assembly we probably need to define a few things a bit more than I have thus far in the context of these posts.
In general, bootstrapping usually refers to a self-starting process that is supposed to proceed without external input. In computer technology the term (usually shortened to booting) usually refers to the process of loading the basic software into the memory of a computer after power-on or general reset, especially the operating system which will then take care of loading other software as needed.
A Composition Root is a (preferably) unique location in an application where modules are composed together.
So how do we defer this choice and keep the flexibility of managing our Composition Root in focused classes?
Before I can answer this question I need to ask another, is the Composition Root part of your application?
The responsibility of the Composition Root is to construct your applications dependencies object graph, and strictly I don't see it as part of the application. Any system has boundaries between different logical puzzle pieces, all are important, but there is one piece that could be considered 'the most' important, that is the entry point, sometimes referred to as main(). Why is this more important than data access or UI? Well, what is the point of writing those modules in the first place if there is no way to execute them? In my mind, the responsibility of main() is to construct and call your application, and the Composition Root is part of that construction.
If you have split your Composition Root up over many projects/modules/plugins, it does not mean that it is part of a particular project/module/plugin it is still on the main() side of the system, it just happens that the code lives in the same house. With this said, having a collocated Composition Root pushes the argument to one of maintainability. The fact the code that defines the object graph is located in the same project helps me rationalise things better. The boost I get to understanding the logical pathways along with the reduced context switching outweighs the additional reference in the project.
There is one caveat to the above, building a plugin that you intend to share. I may love Simple Injector, but like politics and religion, your choice of a DI container is a personal one so don't force it on others :) So what do we do in cases like this?
I have been working on a set of reusable NuGet packages the distil a lot of the concepts in my blog posts for the Sitecore CMS. To address the fact that not everyone would want to use Simple Injector (even though I don't know why that would be ;) for each feature that depends on a DI library (like Application Containers) I created two packages, one for Simple Injector and one for DryIOC. The other side of this coin is to document how I have created these packages so others can contribute, adding implementations for their DI framework of choice.