I recently started exploring the new Visual Studio 2010 code editor. The great thing about the new editor is that it supports plugins. You’re able to write additions to the Visual Studio editor that formats the code in any way you like. Microsoft put up some samples on CodePlex. Visual Studio uses the Managed Extensibility Framework (MEF) as the base for writing plugins. In this post I’d like to give you the basics of the Managed Extensibility Framework. After that, I’ll explore writing plugins for Visual Studio 2010.
What problems does MEF solve?
MEF presents a simple solution for the runtime extensibility problem. Until now, any application that wanted to support a
plugin model needed to create its own infrastructure from scratch. Those plugins would often be application-specific and could not be reused across multiple implementations.
- MEF provides a standard way for the host application to expose itself and consume external extensions. Extensions, by their nature, can be reused amongst different applications. However, an extension could still be implemented in a way that is application-specific. Extensions themselves can depend on one another and MEF will make sure they are wired together in the correct order (another thing you won't have to worry about).
- MEF offers a set of discovery approaches for your application to locate and load available extensions.
- MEF allows tagging extensions with additional metadata which facilitates rich querying and filtering
I copied the above text from the CodePlex MEF homepage. So basically, MEF is a framework that will let you write applications that support plugins very easily. MEF exposes classes, interfaces and services to easily let you write applications that support plugins.
How does MEF work?
Basically, this is how it works:
- Some components (parts of your application, not System.ComponentModel.Component) expose capabilities (or services if you will).
- Some components are dependent on other capabilities.
The goal of MEF is to glue the capabilities and dependencies together in your application. This allows for a very modular design. Exposing a capability in MEF is called an Export and a dependency on an other capability is called in Import.
Let’s take a look at how this works. Suppose we have an application that is able to write tracing messages to some log. One class is going to want to log a message, the other class is going to take care of that. Of course we don’t want having a direct reference from one class to the other, so we’ll use an interface. Just like you’d do in any well designed application.
public interface ITraceMessageWriter
{ void WriteToLog( string message );
}
The next step is to create a class that implements this interface. This class will take care of actually logging the message:
[Export(typeof(ITraceMessageWriter))]
public class TraceMessageWriter : ITraceMessageWriter
{ public void WriteToLog( string message )
{ // write here to any data store (file/database)
}
}
The only thing we added is an MEF attribute: Export. The argument of the Export attribute is the name of a contract. This can be a string or a Type. The purpose of this attribute is to link the right services to the right dependencies. So the next piece of code shows how to import a dependency:
public partial class Window1 : Window
{ [Import]
protected ITraceMessageWriter _writer;
To make sure the _writer field actually gets a reference to an instance, we make sure MEF is going to ‘compose’ our object. To do this we call a method called Compose in the constructor. This method is one we’re defining later and will make sure that MEF fills our field. After that we can call methods on it. Note that there’s no guarantee that the field will actually be filled. In the case that there’s no Export (service/capability) found for this dependency, the field would still be null.
public Window1()
{ InitializeComponent();
Compose();
_writer.WriteToLog("Hello World");
}
The Compose method does all the MEF magic. In this Compose method, we need to do a couple of things.
- Create a CompositionContainer. This container is used when composing objects.
- Tell which object or objects needs composing (have their dependencies resolved).
To do this, we need a CompositionBatch. An object which holds references to all objects that need to be composed.
- Tell which extensions/plugins need to be searched for Exports
In MEF we need a Catalog for this. A Catalog defines the location of one or more extensions. In this example, I’ll be using an AssemblyCatalog. A Catalog referring to an already loaded assembly
Fortunately, the resulting code is pretty easy:
private void Compose()
{ AssemblyCatalog catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
CompositionContainer _container = new CompositionContainer(catalog);
CompositionBatch batch = new CompositionBatch();
batch.AddPart(this);
_container.Compose(batch);
}
This is what we did:
- We created a catalog for the current executing assembly
- We created a container to do the composition
- We added ourselves (since ‘this’ has the _writer field) to a CompositionBatch.
- We called Compose on the container passing in the CompositionBatch.
That’s all. Our dependency is resolved by MEF and we’re ready to go. Admittedly, this is a extremely basic example. But remember that the dependencies we have may resolved from plugins that are loaded dynamically from a given directory. Or from registered plugins in a config file.
Isn’t MEF just another Dependency Injection framework?
No, not really. Although MEF does have some capabilities that DI-frameworks have, MEF’s focus is on composition. Some classes import services from other parts of the application, and some classes export services. The goal of MEF is to seamlessly glue those together. One other difference is that normally when using a DI-framework, you are aware of all the components used in the application. In MEF, this may not be the case. You load up some extensions or plugins or whatever you want to call them, and MEF discovers all the exports and imports of services in those extensions. Therefore, the actual functionality of the application is dependent of the extensions that are loaded at a given time. This is uncommon in ‘normal’ DI scenario’s.
Where and when is MEF available?
Whenever you use the .NET Framework 4.0. As MSDN says: “MEF is an integral part of the .NET Framework 4 Beta 1, and is available wherever the .NET Framework is used. You can use MEF in your client applications, whether they use Windows Forms, WPF, or any other technology, or in server applications that use ASP.NET. In addition, there are plans to add MEF support for Silverlight applications.”
So it’s going to be a part of the Framework 4.0. Until then, MEF can be downloaded from here.
Where do we go from here?
If you’re interested in MEF, I’d suggest you read at least this overview on MSDN and Brad Abrams Simple Example of MEF in Silverlight. That should give you a good headstart.