Intro to MEF

“The Managed Extensibility Framework or MEF is a library for creating lightweight, extensible applications.” More information’s at MSDN (http://msdn.microsoft.com/en-us/library/dd460648.aspx)

As short example below:

I’m thinking of an application which can dynamically load functionality. In this kind of applications you will provide a default implementation of something, but you will also offer a way for the user to customize that implementation somehow.

I will create a simple console application in C# and make use of a property called “message” and this app will discover all messages available. Just pretend that the message you will see is a functionally/module.

Catalogs are responsible for discovering what is to be imported or exported. AssemblyCatalog will search in the current assembly and the DirectoryCatalog will search for messages in any dll’s which will be found in root of the app.

AssemblyCatalog assemblyCatalog = new AssemblyCatalog(Assembly.GetCallingAssembly());
DirectoryCatalog dirCatalog = new DirectoryCatalog(AppDomain.CurrentDomain.BaseDirectory);

Because CompositionContainer works with catalogs, we aggregate both catalogs in a single one and pass it over to container. The container is responsible with composition.

AggregateCatalog defaultCatalog = new AggregateCatalog(dirCatalog, assemblyCatalog);

CompositionContainer compositionContainer = new CompositionContainer(defaultCatalog);
compositionContainer.ComposeParts(this);

In the code that’s follow up, I will make use of the import/export attributes. Both of then supports a parameter that indicates the contract name, so you can export something under a contract name and also import only that thing that has that contract name.

Somewhere in the application I will export or mark the possible module/logic that can be used:

[Export("C")]
public string Message
{
   get { return "MessageFromLib"; }
   set { }
}

Elsewhere in the app you will want to use it, then:

[Import("C")]
public string ImportMessage { get; set; }

In the previous example you can see that I explicitly tell to MEF that I want that message that was exported under the “C” contract name. And it works! 🙂

But, if I said that in a regular app will provide a basic implementation, so in other words, I will need be able to import multiple modules of the same type and based on some logic use the one that may be has new version.

[ImportMany]
public Lazy<string, IMessageMetadata>[] AllMessages { get; set; } 

And guess what, I will say just give me all the things that are exported under the type ‘string’ (ImportMany attribute). You can see there is an interface type (it’s optional), very useful for passing in the metadata associated with that object (as I said, a version number or a date…)

How I declared that:

class AbetterMessage
    {
        [Export()]
        [ExportMetadata("Inside", false)]
        public string Message
        {
            get
            {
                return "AbetterMessage";
            }

            set {}
        }
    }

How IMessageMetadata interface is declared:

public interface IMessageMetadata
{
   bool Inside { get; }
}

MEF will know to bind values based on property names doing a little bit of reflection.

The trick is that the second implementation will be in a separate DLL that need to be copied in the root of the app. The demo project has two projects. One called MEFBasics (a console app) where is all the plumbing and a class library project DLL that is set to be copied in the MEFBasics output, but it has no reference between them.

Download example from here.

Advertisements