Endjin - Home

Component discovery and composition Part 1f: Fundamentals – Generalizing Registration

by Matthew Adams

Combining MEF With Castle.Windsor For Low-Ceremony Component Composition

Last time, we looked at a method we could use to componentize feature registration. This time, we’re going to go on and look at a means of generalizing this, and a nifty pattern you can use with C# generics to help us out.

Generalization

One of the most important features of this conventional approach to configuration is that it is generalizable. We don’t have to implement these installers by hand every time. We can generalize a particular convention into a base class, and then simply inherit from the base to provide the specific installers we need for a component.

Here’s an example of a generic base class for an interface-based installer.

public abstract class InstallerBase<t> : IWindsorInstaller
{
    private readonly IEnumerable<type> markerTypes;

    protected InstallerBase(IEnumerable<type> markerTypes)
    {
        if (markerTypes == null)
        {
            throw new ArgumentNullException("markerTypes");
        }
        this.markerTypes = markerTypes;
    }

    public void Install(IWindsorContainer container,
                        IConfigurationStore store)
    {
        foreach (var type in this.markerTypes)
        {
            container.Register(
                AllTypes
                .FromAssemblyContaining(type)
                .BasedOn<T>()
                .WithService
                .FromInterface()
                .Configure(component =>
                    component.LifeStyle.Transient
                .Named(component.ServiceType.Name)));
        }
    }
}

Because we so often have just a single assembly associated with a component or a group of components, we can also provide a generic base to help us out in that scenario.

public abstract class InstallerBase<T, M1> : InstallerBase<T>
{
    protected InstallerBase()
        : base(new[] { typeof(M1) })
    {
    }
}

The second type parameter is the type of the marker, which we then pass into our base class constructor. So here’s a base for view installers derived from that (notice how we’ve now codified the convention that views implement some IView interface).

public abstract class ViewInstallerBase<T>
    : InstallerBase<IView, T>
{
}

So finally, when you want to create a view installer for a specific assembly containing view components, it just looks like this.

[Export(typeof(IWindsorInstaller))]
public class ViewInstaller
    : ViewInstallerBase<ViewInstaller>
{
}

Notice how we’re passing our own type as the type parameter of the base view installer, so we’ll be installing views from the assembly in which our installer is located, and we’ve decorated the concrete installer type with the MEF export so that it can be discovered by the bootstrapper.

Conclusions

We’ve now got a very powerful technique for the componentization of the container bootstrapping and installation process itself, with low impact on our domain classes and a good deal of extensibility. However, we have taken explicit dependencies on MEF and Windsor in the process. Although our 3-calls model attempts to hide these dependencies from the consumer, or at least to isolate them to well-known pieces of code, we’d like to do better than that, and deal with an abstraction of the container as far as is possible. It also allows for the possibility of swapping out the container implementation (to use Unity, or NInject, for instance) if a particular project or client has standardized on a different technology, or when we need to upgrade to take advantage of some future full-featured MEF-based container, for example.

So, in the next part, we’ll look at a framework we can use to abstract the container for the consumer, while retaining the ability to take advantage of all of its features in the registration process.

More reading on MEF and Windsor

If you’re not familiar with MEF, then there are plenty of getting-started resources. Glenn Block (MEF’s progenitor) has a great deck and code samples here, although they do lack Glenn actually talking you through it. So you shouldn’t miss his series of articles (from a Silverlight perspective, but mostly applicable to other applications like WPF, Windows Forms, console, or whatever…) here. Brad Abrams has also blogged about it here in a conveniently bite-sized “getting started” kind of way, although it is talking about a pre-release build.

Matthew Adams on Twitter

About the author

Matthew was CTO of a venture-backed technology start-up in the UK & US for 10 years, and is now a Founder of Endjin Ltd, which provides technology strategy, experience and development services to its clients who are seeking to take advantage of Microsoft Azure and the Cloud. You can follow Matthew on twitter.