If your application needs extension points what do you do? Building a plugin based system is not cutting edge, it is not rocket science. However, it does take a little effort and can be a bit painful depending on your implementation. The guys at MS (Glen Block and crew) has been working on this kickin framework for about a year now called the Managed Extensibility Framework (most commonly known as MEF). The core goal of MEF is to simplify the creation of extensible applications. MEF offers discovery and composition capabilities that you can leverage to load application extensions.
There are a metric crap-ton of samples out on the net which show how to get running with MEF, however many of the posts are based off of older previews and most are also incomplete in terms of the code they show you on screen. What I would like to do is provide a detailed how-to on getting your first (simple) MEF application up and running.
Goal of the demo code?
For this demo code we are going to put together a very simple rules plug-in engine. The goal is to be able to add in a new IRule at any point and have your application pick it up.
What is needed?
If you have not already done so head out to http://mef.codeplex.com/ and grab the latest source download. More than likely you will need to download and compile all the source in order to get working binaries (hey, it is a preview after all). Once you have compiled the source you need to grab the output from the ComponentModel project (assembly name is System.ComponentModel.Composition) and include this into your project.
Putting it together?
Creating the rule Interface : IRule
This is needed because in order to define a plug-in you need to define what that plug-in looks like.
public interface IRule
{
void DoIt();
string Name { get; }
string Version { get; }
string Description { get; }
}
Creating a rule instance (or two)
Now that we have our rule interface we need to create specific instances of the rule and mark them for export. Marking them for Export simply entails adding a attribute provided by the MEF framework and this attribute allows you to describe your plug-in to the MEF framework so it can pick it up.
[Export( typeof( IRule ) )]
internal class RuleInstance1 : IRule
{
public void DoIt() {}
public string Name
{
get { return "Rule Instance 1"; }
}
public string Version
{
get { return "1.0.0.0"; }
}
public string Description
{
get { return "Some Rule Instance"; }
}
}
[Export( typeof( IRule ) )]
public class RuleInstance2 : IRule
{
public void DoIt() {}
public string Name
{
get { return "Rule Instance 3"; }
}
public string Version
{
get { return "1.1.0.0"; }
}
public string Description
{
get { return "Some Rule Instance"; }
}
}
Creating the holder for all your plug-ins
In order to have your application know about the plug-ins that MEF has found you need to define a storage location for them. We will do this by creating a property of IList<IRule> which will hold each instance. When we create this storage location we need to tell MEF that we are going to use this as a storage location and to do this you need to mark it with the ImportMany (use this attribute if you want a collection, use Import for only a single instance) attribute. This is another special attribute provided by the MEF framework.
[ImportMany( typeof( IRule ) )]
internal IList<IRule>: _rules { get; set ;}
Creating the logic to load the plugin
Now that we have all the heavy lifting out of the way in terms of defining our Imports and Exports it is time to setup our application to consume the data. It is here where you tell MEF where to look to find your exports (plug-ins) and what to do with them once you have found them.
public void Init()
{
var catalog = new AggregateCatalog();
var container = new CompositionContainer( catalog );
var batch = new CompositionBatch();
batch.AddPart( this );
// because all our types are in the same assembly we simply use the current one.
catalog.Catalogs.Add( new AssemblyCatalog( Assembly.GetExecutingAssembly() ) );
container.Compose( batch );
foreach ( var rule in _rules )
{
Debug.WriteLine( rule.Name );
}
}
Wrapping it up
As you can see getting a simple example of MEF up and running is a pretty simple task (great job MEF team). You should be able to get this up and running in about 10 minutes. You should also have all the code you need in order to get this running. I hope this helps kick-start someone’s learning and adoption of MEF.
Till next time,
Posted
10-27-2009 5:34 AM
by
Derik Whittaker