Component discovery and composition Part 1e: Fundamentals – Componentizing Registration
Combining MEF With Castle.Windsor For Low-Ceremony Component Composition
Componentizing registration
In the last post, we'd got down into the detail of the Windsor container's conventional registration model.
Before we move on, let's wind back up to the top of the stack and remind ourselves of the key objective. We want to componentize our software – packaging it into well-defined units that are self-describing, and self-managing with a minimum of well-understood dependencies. Part of that self-management is achieved by declaring our dependencies by convention (via our injecting constructors), and by choosing our interfaces and namespaces to support those conventions. But we can componentize registration too, by providing the means of registering the types in a class right along with the component itself.
That any given installer takes a dependency on other types defined within the component and its assembly or package is no problem – the installer is a part of that component (i.e. inside the dependency boundaries).
When we bootstrap our container, we can then discover just the installers within each component using the higher-ceremony MEF technique, gaining all the advantages of Silverlight package support and dynamic composition as new components are added. Within the installer, we use the low-ceremony conventions of the Windsor container so that regular developers don't have to deal with our installer infrastructure at all.
You can see this illustrated in the diagram below.
We've added a ViewInstaller, a TaskInstaller and a ViewModelInstaller to the component. You can see that they implement an interface called IWindsorInstaller. Let's look at the code for the ViewInstaller to see how that works.
The IWindsorInstaller interface requires us to implement a method called Install(), which passes us a container (and a configuration store, which is the subject of a later post). We can then call our registration methods on that container; in this case, registering anything in the assembly that implements IView.
Notice how we're using the installer type itself as the "marker" type from the previous installer. We're going to install every view we find in the same assembly as the installer itself (as per the diagram above).
We also mark our component with the MEF ExportAttribute. So now, we can find our installers using MEF, without taking a dependency on the assemblies themselves, and then install the components we find in those assemblies.
Here's some example code to bootstrap the Windsor container using this technique.
Finally, the only code you need in the client is a call to the Install() method on the container to complete the configuration process.
The fact that we are using the installer itself as the method by which we locate the components to install means that we only actually need one of these installers for each convention, in each assembly containing components to be installed.
So typically (once the project has been set up for the assembly) developers will just create their components in the assembly, conforming to the standard naming conventions, implementing their interfaces and providing the right methods, and their classes will automatically be bootstrapped into the application container.
We then have the bones of a generalizable solution. We'll put some more flesh on those bones next time.
If you're not using Silverlight XAPs, you've not got complex assembly resolution, and you don't need re-composition, you don't actually need to use MEF at all. In the next section of this series, we'll look at an abstraction over the container that allows you to choose different bootstrapping techniques depending on your particular scenario.