It’s not uncommon to want to dynamically add new sections to an XML file, such as a config file, without having to recompile existing code for processing said XML file. One common example is the way that .NET’s app.config file supports a config section / config section handler model. You can add new arbitrary XML that is specific to a particular bit of code in its schema, then register a “handler” for that config section so that the standard System.Configuration classes can read and deal with that otherwise unknown schema.

Rather then explicitly registering “handlers” in the XML file itself, we can use the Managed Extensibility Framework (MEF), which is now a fully baked part of the .NET 4 framework.

I want to be able to add new <product> sections in the future which will contain XML that only that particular product’s plugin will know what to do with.

MEF is all about the “plugin” pattern. It allows me to declare “Exported” contracts that plugins essentially publish for use, and to declare that other components “Import” those plugins, meaning they require a runtime instance of one or more of those published exports. For the sake of the above example, I’ve defined an interface that each product plugin will need to support to process the XML from its config section.

interface IProductPlugin
{
bool Configure(XElement config);
}

When the overall XML file is processed, an instance of each product’s plugin will be instantiated and “fed” the XElement that represents its config section. MEF makes it easy to choose which plugin gets loaded for each section using named contracts. The following two plugins

both export the IProductPlugin interface, but they also declare a name under which it will be exported. We can use a corresponding “name” attribute in the <product> element of each section to get the right plugin. At runtime, the code to load the file reads each product element and instantiates the right plugin by asking MEF for the named instance from MEF’s catalog.

The key in this case is the GetExport method. It optionally takes that arbitrary string and tries to find the right instance from the catalog. In this particular case, for the sake of simplicity, the catalog is loaded from the running assembly.

In practice, I would use the DirectoryCatalog class to build the catalog from all the assemblies in one directory, which would allow new plugin assemblies to be simply dropped into place without anything needing to be compiled.