Last Friday Managed Extensibility Framework Preview 2 (MEF) was published on CodePlex. MEF is a new library in .NET that will simplify adding extension points to your applications. It enables discovery, loading and composition of the extensible components. You can now download the source code, samples and find more information on the project site: http://www.codeplex.com/MEF

I was playing with the bits over the weekend and chatted with Glenn Block (Program Manager on the .NET FX team that does MEF), who explained to me what MEF can do for us. I thought it would be beneficial to share this information, so I created a sample to demonstrate how MEF can be hosted in your application. Please note that this covers only a single scenario where I found MEF might be useful, but MEF probably can do much more for you.

Before we go any further you might want to download the sample project, so you can browse the source code while I walk through it:

Sample scenario

So here is my sample scenario: Let's say you are building a Windows Forms application where you want to add browser like navigation capabilities. This means that your window contains a placeholder where you can load other "pages" be specifying only the page name. Sounds familiar? Yes, WPF supports this out of the box with then NavigationWindow and Pages. So in short we would like to build a NavigationWindow for Windows Forms.

Let's assume that our pages would be simply UserControls. Actually it is quite easy to load user control dynamically - you simply instantiate the control's type and add it to parent's Controls collection. The real problem here is how to map page name (string) to it's type.

For example we could create a section in app.config file that lists all available views and map their names to the corresponding types. This could look similar to this:

Then we can scan the current assembly for all types that have this attribute (using reflection), construct a dictionary of all pages, and when requested create instances of a specified page (with reflection again).

But guess what... MEF already does all this for us with much less code. Let me show you how.

Exports

Very simple. Only odd thing is that this attribute itself need to be tagged with MetadataAttribute so MEF knows to expose it as metadata in the parts catalog (and we will use it in just a moment). Now we can use it on any UserControl to assign the page name, but we need to use it together with the Export attribute. Type discovery in MEF is based on attributes and Export indicates that the attributed class should be exported as ComposablePart and specifies the contract it implements (it is Page in our case):

Notice that in MEF contract is specified as string. There is additional overload on the Export attribute that consumes a Type, but internally it would be converted to a fully qualified name of that tape. On the side note, even when you use a typed contract the attributed class doesn't really need to implement it - the contract type is used only as a key in the container.

CompositionContainer and Catalogs

Now we can start implementing our NavigationWindow and first thing to do is to configure the CompositionContainer:

Because we want MEF to discover all the pages in the current assembly we use the AttributedAssemblyPartCatalog that will search for all types that were attributed as exports. Catalogs are responsible for creating a Resolver that is then passed to the CompositionContainer so it can query for available ComposableParts (you can learn about the other two types of catalogs from the programming guide). Next we also register the NavigationWindow itself as a ComposablePart in the container. After doing so we need to call the Compose method to resolve dependencies (note that you don't need to call Compose to user parts exposed from catalogs). But for this to work properly we need to add Export attribute on NavigationWindow too:

The Import attribute indicates that container should resolve this dependency for us by assigning a collection of all exports with Page contract (this happens when you call container's Compose method). It will also expose the PageMetadataAttribute through IPageMetada interface:

public interface IPageMetadata
{
string PageName { get; set; }
}

Notice that we didn't implement this interface earlier on the attribute itself. At runtime MEF will be able to create dynamic proxy to it with a magic thing called duck typing. Isn't that cool!

The _pages field is private and normally it wouldn't be resolved, but we can ask MEF to handle it by adding the assembly level AllowNonPublicComposition attribute (add it to AssemblyInfo).

Now we are ready to implement the GoTo method that will do the navigation:

In the first line it will search the _pages collection for one with specified page name (MetadataView property implements our IPageMetada interface). Later when the page was found we request the instance of UserControl with call to GetExportedObject(). I told you this would be easy!

Now we can put the NavigationWindow on any Form and call navigationWindow1.GoTo("Page1") to get this:

I assume that we would like to navigate from one page to another by clicking the link. Therefore the page needs to know the NavigationWindow it is hosted in – in other words it has a dependency on the NavigationWindow.

This is why earlier we registered the NavigationWindow itself as a ComposablePart, so now we can import it from any other part. This would get us to the second window:

Object lifetime

To make this exercise more interesting here we have a TextBox and we want to pass its value to the third window. But first let's talk briefly about part's lifetime. By default all the exported parts are treated as singletons. For us this means that there would be only a single instance ever created of each page (as soon as you call Export.GetExportedObject method). Of course this is not always the desired scenario, and you can change this behavior using the CreationPolicy property of the CompositionOptions attribute. Here is Page1 revisited:

The CreationPolicy enumeration has only two values: Singleton (default), and Factory.

Looking back to our scenario we want to make the second page a singleton so it can be accessed from the third page. To access it would also need to get a reference to the Container – and again we do this by adding another dependency in Page3:

Now, this dependency won't be available just yet. As we've seen before the container was created by the NavigationWindow. We could register it manually as we did with the NavigationWindow, but I would like to show you one more capability that MEF has – you can declare Exports not only on types but also on the class members:

[Export("Container")]
private CompositionContainer _container;

So when we add this field to NavigationWindow we now not only export the NavigationWindow itself but also the value in the it's _container field. I can imagine that this capability would be handy if you need to export one of the built-in system types or type from a third-party library when you can't add the Export attribute directly on the given type.

Finally here is the code from Page3 to get the reference to previous page and read the value entered in the TextBox:

This time we used one of container's GetExports methods to query for a page (ComposablePart with contract "Page") and with page name of "Page2" (through Metadata dictionary). The query capability on metadata is one of the big things in MEF and it allows you to get detailed information about available parts even before you instantiate them. I've also added IAskNamePage interface so we can get the text entered on Page2:

public interface IAskNamePage
{
string FullName { get; }
}

It simply returns the text from TextBox:

public string FullName
{
get { return textBox1.Text; }
}

Here is the last page:

Summary

I hope that this example gives you some idea where MEF fits and will help you get started. Let me know if you have any questions about this. For more advanced scenario check out the three samples that shipped with the current drop on CodePlex:

I upgraded the MEF to version 3 just out.The intended logic in your demo by recreating the Page3 each time you visit the page stopped working.Same instance is returned each time.It seems to be quite cumbersome to get this behaviour in version 3.Any pointers?CheersDitlef

This post is really great! I have been searching for some information about the Managed extensibility framework and accidentally I have noticed this headline. As I see, this site is full of more such great posts like this one so I will definitely bookmark it. Thanks a lot one more time.