Addicted To MEF – Part 1

Writing

As with any new tool that hits the scene, I always feel the need to explore and evaluate it. Right now there are many many new tools coming out of Microsoft and so I have to cherry pick the ones I am most interested in. Well, I saw just a few days ago that Microsoft had just released Preview 3 of its Managed Extensibility Framework, also known as MEF. I’ve been reading about it for a while, and I know that two people that I admire, Glenn Block and Hamilton Verissimo (of Castle fame) are both working as PMs on the team. I have also recently been working on a lot of architecture design stuff for my employer (Dominion Digital) and so I was very interested to explore MEF further and see what it could offer me.

Before I go further, you must realize that I am exploring this technology, so if I state something wrong, please call me out!

I’ve heard in a few spots that MEF is a bit like a DI Container, but it is more about application composition than dependency injection. In its most basic use case you can define exports (using the “ExportAttribute”) and then define imports (using the “ImportAttribute”). We will start off with a very simple example, and then elaborate upon it a bit to show you how this works.

So let’s say that we have an interface which looks like this:

public interface IConsoleWriter
{
    void Write(string message);
}

We are simply going to use this interface to write out to the console, and if you didn’t pick up on that, then you are a tad slow. 🙂 Anyways, so we need to consume this in my application, so we are going to define a class which implements this interface:

public class RedConsoleWriter : IConsoleWriter
{
    public void Write(string message)
    {
        ConsoleColor originalColor = Console.ForegroundColor;
        try
        {
            Console.ForegroundColor = ConsoleColor.Red;
            Console.WriteLine(message);    
        }
        finally
        {
            Console.ForegroundColor = originalColor;    
        }
    }
}

This particular implementation will now write out the value to the console in red! How cool! (sarcasm) Normally if we wanted to use this class, we could do something like this:

IConsoleWriter consoleWriter = new RedConsoleWriter();
consoleWriter.Write("Hello from the console!");

But we obviously are not interested in doing that here, MEF is all about extensibility, so lets make this puppy extensible. The first step that we have to take is to put an “ExportAttribute” on the “RedConsoleWriter” class to tell MEF that this is a type which we are exporting. In this attribute we will also tell MEF which type this class is exported for:

[Export(typeof(IConsoleWriter))]
public class RedConsoleWriter : IConsoleWriter
{

MEF now knows that this class is being exported for the “IConsoleWriter” interface. The next step is for us to import this guy. In order for us to do that we have to use two different classes. This is where the framework starts to feel a bit overly complex, but I’m sure as I explore it more I’ll see why this complexity was introduced.

The first class that we have to use is the “AttributedAssemblyPartCatalog“, which is a bit of a mouthful. This is one of four types of catalogs available to you. Catalogs are merely a method of gather up exports in different ways. The four types of catalogs are:

AggregatingComposablePartCatalog – Combines multiple catalogs into a single catalog. Useful if you need to gather exports in multiple different ways.

AttributedAssemblyPartCatalog – This is the one we are going to use, it takes an assembly and gathers up all types which are marked with the “ExportAttribute”

AttributedTypesPartCatalog – Looks for exports given particular types.

DirectoryPartCatalog – Watches a folder and enumerates assemblies to find exports

Next we are also going to have to use a “CompositionContainer” class, which takes a catalog and provides the ability to expose the catalog’s exports. Make sense? Let’s take a look:

private void Compose()
{        
    var catalog = new AttributedAssemblyPartCatalog(Assembly.GetExecutingAssembly());
    var container = new CompositionContainer(catalog);
    container.AddPart(this);
    container.Compose();
}

Here we are creating our catalog by passing in the current assembly, then we pass our catalog to the container constructor. The next line just passes in the current class (the “Program” class, since this is console app) to the container so that its imports will be resolved. Then we call “Compose” on our container, and that is it, our container has now been configured with all of our exports. But how do we get our exports into our application?

We do this by putting an “ImportAttribute” on the properties that we want to have “composed” by the container. So, we declare a property with the “IConsoleWriter” type, and we put the attribute on it:

[Import]
public IConsoleWriter ConsoleWriter { get; set; }

Pretty simple. Now we have to run our Program, but we have to create a new instance of our “Program” class since our property is not static. Our whole “Program” class ends up looking like this:

internal class Program
{
    [Import]
    public IConsoleWriter ConsoleWriter { get; set; }

    public static void Main(string[] args)
    {
        var p = new Program();
        p.Run();
    }

    public void Run()
    {
        Compose();
        ConsoleWriter.Write("Hello from the console!");
    }

    private void Compose()
    {        
        var catalog = new AttributedAssemblyPartCatalog(Assembly.GetExecutingAssembly());
        var container = new CompositionContainer(catalog);
        container.AddPart(this);
        container.Compose();
    }
}

Notice that we are just using the “ConsoleWriter” property without ever assigning anything to it. By adding “this” to the container and calling composed, all “Import” attributes will be found on this type and MEF will assign a part to it. This works because we only have one export for the “IConsoleWriter” type, if we had more in this assembly then MEF would not know how to resolve it:

MEF Multiple type fail

But if we change our application to have an IEnumerable<IConsoleWriter> property, then we will get a list of all of the exported types:

internal class Program
{
    [Import]
    public IEnumerable<IConsoleWriter> ConsoleWriters { get; set; }

    public static void Main(string[] args)
    {
        var p = new Program();
        p.Run();
    }

    public void Run()
    {
        Compose();
        foreach (IConsoleWriter consoleWriter in ConsoleWriters)
        {
            consoleWriter.Write("Hello from the console!");   
        }        
    }

    private void Compose()
    {        
        var catalog = new AttributedAssemblyPartCatalog(Assembly.GetExecutingAssembly());
        var container = new CompositionContainer(catalog);
        container.AddPart(this);
        container.Compose();
    }
}

That is pretty cool. Now we are looping through our “RedConsoleWriter” and our “BlueConsoleWriter” and writing each out to the console:

image

Neato.

Well, that was just a quick look at some of MEF’s most basic features, but in the next post I’ll take a look at some of the other catalog types and how we can use them in order to really start adding external plugins to our application. Hope you found this useful!

Download the Full Source Here

Loved the article? Hated it? Didn’t even read it?

We’d love to hear from you.

Reach Out

Comments (18)

  1. @CarlH I don’t see why you can’t use it in asp.net, I’ll try to throw together an example soon.

    @Marcus Yep, I was being lazy, I just attached the source to the end of the post. And yes, currently the Exports are inside of the same dll, but in a future post I’ll show you how to easily import from an external dll. MEF handles it all for you transparently, it can even watch a folder for you and import new types as they are added.

  2. @Rasmus In fact, it does less than most DI containers. But it does a few different things since it is geared toward composable software rather than dependency injection. In future posts you’ll start to see some of the differences.

  3. MEF is really cool, but I still struggle to find a place for it in any application that I write. A DI container usually gives me the flexibility that I need (I know they aren’t exactly the same thing). I don’t find myself writing a lot of pluggable architectures(wish I was), which MEF is geared towards.
    Maybe you should get a couple developers together and set out to incorporate a bunch of Microsoft technologies into a product, kind of like DinnerNow, I’d be game. Good Post Justin!

  4. Nice post Justin. I am blushing on the admiration comment 🙂

    Anyway, I think we need a way to trim the bootstrap code even further. I have actually been playing around with a MEF hosting class which eliminates the need to even create the container. Instead you call a Host.Run(args) method.

    The host class lets you pass a param array of paths in it’s constructor and automatically adds the current assembly. Then the host looks for an import of [IMEFApplication] and calls it’s Run method.

    Using this approach the Compose method goes away completely and is replaced with a

    class Program {
    static void Main(string[] args) {
    var host = new CompositionHost(@".Extensions");
    host.Run(args);
    }
    }

    [Export(typeof(IMefApplication))]
    public class MEFApp {
    [Import]
    public IConsoleWriter ConsoleWriter { get; set; }

    public void Run(string[] args) {

    }
    }

    What do you think?

  5. @Khalid I agree with you that if you aren’t developing pluggable applications, then you probably have no need for MEF. But that is by design. And yeah, it would be cool to have a good demo thrown together, but the MEF source already comes with some pretty good demos!

  6. @Glenn Hey, thanks for the comments!

    I think it is an excellent idea to reduce ceremony around the code whenever possible. The current way it has to be bootstrapped feels awkward, and I think your example feels much more straight forward.

    The only downside I see is in the "IMefApplication" magic that gets introduced, but that it something that people will pickup quickly from documentation.

    I have to wonder though, would it be possible to put the IMefApplication interface on the "Program" class and set it as the export? Then you would eliminate the need for the extra class altogether.

  7. @Justin you could surely put it on the program class, as it’s just an export. The only reason I put it in a separate class was for clarify. Another idea would be to not discover it magically, but make the method generic with a constraint on the class implement IMefApp (or IAppRunner which was suggested from a bunch of folks).

    Would you prefer this approach of having the type in hand and you pass it in? Or a hybrid where I can either call passing a param or not?

  8. @Glenn Yeah, making it not discover it magically would be nice. I think it would make the code more explicit. I’m not sure if a hybrid approach is necessary, I guess it depends on how much ambiguity it would introduce.

Leave a comment

Leave a Reply

Your email address will not be published. Required fields are marked *

More Insights

View All