Barbarian Meets MEF (Managed Extensibility Framework)... And There Are Evil Wizards Too
The “barbarian meets” series are a collection of articles that intend to introduce and explain useful libraries, frameworks, tools and technologies in simple and straightforward terms.
MEF is Microsoft’s solution for easing the pain of building extensible applications. Throughout these Barbarian Meets series we will go through what MEF is, why should you care, which problem does it solve and how it works.
- Introduction to MEF
- MEF Architecture
- Dive Into The Attributed Programming Model
- Lifetime and Scope Considerations
- How to Debug MEF
- Inside the Source Code
MEF?
MEF is a highly specialized .NET open source library that aims to provide a standard for developing extensible applications in .NET. By providing a very simple programming model based on attributes and a reduced number of core components, MEF gracefully solves a lot of the pain points that usually accompany extensibility scenarios such as plugin discovery or plugin communication.
How Does MEF Work?
MEF is based around the concept of extensibility by composition of parts. Within MEF’s domain we can distinguish a number of elements:
- Parts are the cornerstone of MEF. Parts known as Exports can provide services to other parts whilst parts known as Imports consume services from other parts. It is throught this relationship between what a part needs, and what a part can provide that the composition takes place. Service definition is done via Contracts.
- Containers perform the actual composition between parts by matching Exports with Imports, that is, service providers with service consumers.
- Catalogs are in charge of part discovery. Using different built-in catalogs, an application can find parts within a given assembly or a given folder at runtime. Containers use catalogs to find out which parts they can use during composition.
In summary, we have some parts that provide services and other parts that consume services. At runtime, we find these parts using a catalog, and compose them using a container. The container analyzes the different contracts associated to each part, and makes the best matches.
An Illustrative Example
Ok. Let’s analyze a useful, interesting yet simple real-world example… eehhhh… let’s say we want to make an RPG ^_^.
Let’s say we have a class EvilWizard
that represents an evil, malicious, foul wizard. As any evil wizard worth his salt, he has to have a shiny hat, a majestic robe and an arsenal of wicked spells. Now, we would be interested in being able to extend the wizard’s attire and spells in the future, perhaps even the player or other third parties could add their own spell-packs as well. All of this, of course, without the need of modifying the original application (we are already busy with our next game, it is gonna be a boom, something related with birds crashing into pigs, or the other way around).
This is a great scenario for using MEF!
Step 1. Add MEF to our Visual Studio solution
Adding MEF to your VS solution could not be easier. MEF is part of the .NET 4 Framework, so you can just Add a Reference as you would do with any .NET assembly: Add a reference to System.ComponentModel.Composition
.
Step 2. Define the EvilWizard as an Import Part
The next step is to tell MEF that our EvilWizard class is a part. Furthermore, it is an import that is going to consume a series of services, that is, is going to use a Hat service, a Robe service and a collection of ISpell services.
In order to do this, we will use MEF attribute based programming model, and we will decorate the EvilWizard components with the [Import]
and [ImportMany]
attributes as shown below:
public class EvilWizard
{
public string Name { get; set; }
[Import]
public Hat Hat { get; set; }
[Import]
public Robe Robe { get; set; }
[ImportMany]
public IEnumerable<ISpell> Spells { get; set; }
}
If you have not guessed it yet, we use the [Import]
attribute to represent a single service and [ImportMany]
to represent a multiplicity of services. These attributes also represent default contracts, but we will deal with contracts in upcoming articles so do not worry for now.
Step 3. Define the Hat, Robe and Spells as Export Parts
We continue by defining the Hat, Robe and Spells as parts that provide services:
[Export]
public class Hat
{
public string Name { get { return "Shiny Hat"; } }
public override string ToString()
{
return Name;
}
}
[Export]
public class Robe
{
public string Name { get { return "Cloak of Heavenly Wisdom"; } }
public override string ToString()
{
return Name;
}
}
[InheritedExport]
public interface ISpell
{
void Cast();
}
public class LightningSpell : ISpell
{
public void Cast()
{
System.Console.WriteLine("Evil Wizard casts lightning spell!");
}
}
public class SleepSpell : ISpell
{
public void Cast()
{
System.Console.WriteLine("Evil Wizard casts sleep spZzZzzZzZzZZzZ");
}
}
Notice how we used the [Export]
attribute to decorate a class that provides a service and the [InheritedExport]
attribute to decorate an interface and ensure that anything that implements that interface becomes a part.
Step 4. Discover The Parts and Setup The Container
Now that we have all the parts of our system ready, the next step consists in instantiating a catalog that will discover all parts within our assembly:
AssemblyCatalog catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
And passing this catalog to our MEF container so it will know which parts are available in our system:
CompositionContainer container = new CompositionContainer(catalog);
Step 5. Let the magic happen
Finally, composing our evil wizard with other parts (hat, robe and spells) is as easy as:
EvilWizard evilWizard = new EvilWizard();
container.ComposeParts(evilWizard);
And there we have our evil wizard kicking ass:
{% img center /images/barbarian-meets-mef-the-evil-wizard-kicking-ass.png “The Evil Wizard is Kicking Ass” “Screenshot of the Console Output when running the example” %}
Step 6. Extending our RPG
Extending our RPG at this moment (for instance, adding new spells) would be as easy as adding new parts in a new assembly. We can use a DirectoryCatalog
instead of a AssemblyCatalog
to point to a path where we can drop all these new assemblies packed with new spells of destruction and mayhem.
As a final note, you can find the code sample at GitHub.
Summary: Why Should You Care?
By now you should have been able to see use cases and the advantages of using the Managed Extensibility Framework. If not, here goes a summary of what you get with MEF:
- A Microsoft standard for solving extensibility scenarios
- An out-of-the-box attribute based programming model
- An easy way - catalogs - to discover extensions or plugins - parts
- It is super easy to add to your .NET application since it is part of the .NET framework
- It is open source, and fully extensible. If you want, you can replace the attribute based programming model for a programming model of your own. For instance, you could use a centralized configuration of some sort.
- It provides a rich metadata system that allows you to attach any kind of metadata to any part.
References
- Pluralsight: Building Extensible Applications with MEF: Great Pluralsight’s course on MEF by @Dustin Davis
- Glenn Block: Building Composable Apps in .NET 4 with the Managed Extensibility Framework
- Glenn Block on MEF at Hanselminutes
- Glenn Block at .NET Rocks
Continue with MEF Architecture (not yet available).
Written by Jaime González García , dad, husband, software engineer, ux designer, amateur pixel artist, tinkerer and master of the arcane arts. You can also find him on Twitter jabbering about random stuff.