MEF Tutorial (Managed Extensibility Framework)

In my previous post I talked about dot net’s Managed Extensibility Framework. In this post I will be walking through a simple MEF tutorial to show how MEF can be used in an application. Microsoft provide an excellent tutorial on how to use MEF in the context of a simple calculator application, so I’m going to create a simple application that is designed to convert any file type to HTML via the use of plugins.

MEF requires a good use of separation in your code. Keeping your business logic separate from your presentation logic is always a good idea, but in the context of MEF, you will want a separate library that you can distribute to allow the creation of third party plugins so you need to include your contracts in a separate project.

Simple HTML Creator app

To start with, create a simple WPF app called MEFExample (note if you call it something different, you will have to change the namespaces in my examples). Set up the UI to look like the following:

As you can see, we have a button with a click event in our toolbar. We will click this to be presented with a filepicker to select our file to convert. Through clever use of MEF, the filepicker will only display supported files.

The next thing we need to do is add MEF to our solution. Right click on References > Add Reference > Assemblies > Framework, then find and add System.ComponentModel.Composition. This contains all the parts of MEF we need for the demo.

Next we need to define the contracts for our plugins to follow. Create a new project in the solution that is a class library called MEFExampleLibrary. In here we just need to define two interfaces:

IConverterToHtml

This is the contract that our plugins will implement. It is very simple, we require one method to convert a file to HTML. We’ll simply pass a filepath to this and let it figure out what to do with the file. It will give us a string (hopefully of HTML) back.

IConverterToHtmlData

This defines the metadata that our plugin can define. The FileType property will allow us to display only those files which are appropriate, and allow us to pick the right plugin to convert a file once selected. This file is named by a convention MEF defines, by appending Data to the end of our first contract.

Now we have defined our contracts, we can finish our application. We’ll begin by adding MEF magic. First of all, add a reference in our UI project to the Library project we just created. Then in the code behind of the MainWindow.xaml.cs add a using for the library project and the following property:

There are two things to notice here. Firstly, the attribute comes from MEF and you will need a using statement to System.ComponentModel.Composition. This describes that we will want to import the classes defined by our plugins into this property. Simply we tell it to ImportMany which will import all the compatible plugins, if you only wanted to import the first one, you could instead use Import. We also have to give it a type, the contract which our plugins will abide by.

The second thing to notice is we use an IEnumerable of a Lazy class. This means that we only load the plugins if we actually want them, and saves on processing. Our Lazy contains both the IConverterToHtml and the metadata interface too.

To load the compatible plugins we need to call just a few lines of code. Create the following method in MainWindow.xaml.cs:

I’ll step through this line by line. We first start by creating an Aggregate Catalog. In this we define exactly where MEF should look for plugins. On the second line we add a Directory (that we will create later) in our build folder called plugins. This is where we will later add the plugins to load. In the third line we create a container, and this will do our loading of the plugins. We pass it the catalog to look in. Finally inside the try catch, we tell it to compose parts, and pass it the current class. This tells MEF to find anything that requires an Import in the current class and then attempt to import from the catalog. That’s all the code we need to perform the dynamic loading of the external libraries. Far simpler than you might imagine.

Lets now finish the app by creating the click event for the button:

All this does at the start is create an OpenFileDialog. However we then search the metadata of the FileConverters to find all the defined file types of the plugins we have loaded. This way we can present only those files we can support. However by appropriately marking up our plugins with attributes, as we add a new plugin, the open file dialog will now be able to display the extra files supported. The other bit to take note of here is where we set the convertedFile variable. we search through our FileConverters for the one where the metadata matches the extension of the file selected. By then asking for the value (required because it’s a Lazy object) we can then call our ConvertToHtml method. I hope this is fairly obvious what it is doing. The code just searches the loaded plugins to find the appropriate converter for the selected file, based on the metadata for the plugins.

This completes the codebehind for  MainWindow. The completed class should look like this:

So the app is now complete. But it doesn’t yet do anything! So we’d better start get writing a plugin or two. Add two new class libraries to the solution. Call one CsvToHtml, and the other TextToHtml. Add a reference to both System.ComponentModel.Composition and the MEFExampleLibrary to both. In the TextToHtml, create a class called TextToHtmlConverter that looks like the following:

Simply, we implement our interface with this class, and provide the logic for converting a text file to html. As that isn’t the point of this tutorial, I’ve kept the code simple and just added a <br/> at the end of each line. The magic of MEF happens in the two attributes. First we tell MEF the file exports a type of IConverterToHtml. We then also add the FileType metadata, and provide the appropriate filter for the OpenFileDialog. This gives our app all the information it needs to be able to firstly load the plugin, and then the metadata provides the information to use it appropriately. Again, not particularly complex.

Similarly add the following class to the CsvtoHtml library:

Again, same attributes to describe the plugin. The logic simply creates a basic table (Again nothing complex, and will break on anything other than the most basic csv, for example purpose only).

If you ran your project now, it wouldn’t work. That would be because we haven’t setup the plugins folder. The easiest way to do this I find is with a post build action. Firstly lets make sure everything builds when we run (as the two plugin projects are not referenced by the UI). Go to Project > Project Dependencies and select every project for the MEFExample project. This now means all our files build when we run our project. The go to the properties of the MEFExample app, then to the Build Events menu, and add the following build event:

This just simply creates the directory Plugins in the output directory, and copies our two DLLs there for our plugins. This is not necessary, we could do this all manually, it just makes it nicer to debug. The one thing to note is if you make a change to either of the plugins, you will need to rebuild them manually to pickup the changes.

So if you run and debug now you should see the functionality all in place. Further to this, if you want to write extra functionality, you could write another dll that implements the contract and has the appropriate attributes, and drop it in the plugin folder. Next time you load the app, the extra functionality is in place.

The other thing to take note of is when you publish the project, you need to make sure the Plugin folder is created as well (the current setup doesn’t do this). There are several ways of achieving this, so I haven’t included it, probably the best solution is to in code, check whether the folder exists before you attempt to reference it, and create it if it doesn’t.

If you want the example code, you can download it here: MEF Sample Solution

Leave a Reply