Click here to Skip to main content
Click here to Skip to main content

MEFify an Applications

, 7 Dec 2008 CPOL
Rate this:
Please Sign up or sign in to vote.
A very simple example of how to make an existing application extendible using MEF

Introduction

What is your favorite program? Office, Visual Studio, Photoshop, World of Warcraft, Reflector?

What do they have in common? 99% of the most popular software available today is extendable in some way, shape or form. Surely you do not have to be extensible to be popular?

Is the software that you are currently writing extensible? If not, why not?

Extensibility in the past has been extremely hard, you had to do all the work yourself using reflection! Not impossible but in time you will learn that security, isolation, crossing application boundaries & lifetime management is extremely difficult to do yourself! Microsoft also released System.AddIn (Managed AddIn Framework). MAF did make it a little easier once you got your head round the pipeline… but still too difficult to easily add to your application…

Extensibility.JPG

Introducing Microsoft Extensibility Framework

The Managed Extensibility Framework (MEF) is a new library in .NET that enables greater reuse of applications and components. Using MEF, .NET applications can make the shift from being statically compiled to dynamically composed. If you are building extensible applications, extensible frameworks and application extensions, then MEF is for you.

Let's Get Started

I created a pretty simple clone of Window Live Writer. Live Writer has LOADS of plugins available. Each plugin should be capable of adding content to the document.

RudiGrobler.Writter.jpg

Contract

Composable Parts do not directly depend on one another, instead they depend on a contract, which is a string identifier. Every export has a contract, and every import declares the contract it needs. The container uses the contract information to match up imports to exports. If no contract is specified, MEF will implicitly use the fully qualified name of the type as the contract. If a type is passed, it will also use the fully qualified name.

public interface IContentSource 
{ 
    string FriendlyName { get; set; } 
    Nullable<bool> CreateContent(System.Windows.Window owner, FlowDocument document); 
}

Each plugin (Composable part) should have a FriendlyName and add their content into the FlowDocument (by calling CreateContent).

Composable Part

A Composable Part is a composable unit within MEF. Composable Parts export services that other Composable Parts need, and import services from other Composable Parts. In the MEF programming model, Composable Parts are attributed with the System.ComponentModel.Composition.Import and [System.ComponentModel.Composition.Export] attribute in order to declare their exports and imports. A Composable Part should contain at least one export. Composable Parts are either added to the container explicitly or created through the use of catalogs. The default catalogs that MEF ship with identify Composable Parts through the presence of an export attribute.

public class InsertHelloWorld : RudiGrobler.Writter.Common.IContentSource
{
    public string FriendlyName { get; set; }

    public InsertHelloWorld()
    {
        FriendlyName = "Insert Hello World...";
    }

    public bool? CreateContent(System.Windows.Window owner, FlowDocument document)
    {
        document.Blocks.Add(new Paragraph(new Run("Hello World")));

        return true;
    }
}

This is a very basic plugin that only inserts “Hello World” into the FlowDocument.

MEFing the Application

Currently our application is statically compiled. This works… but now I want to add plugins? Even worst… what if you want to add a plugin?

Only 3 changes are required to MEFify your plugin:

  1. Before we can start using MEF, reference System.ComponentModel.Composition.dll (MEF Preview 3).

  2. Decorate your plugin with an Export attribute

    [Export(typeof(RudiGrobler.Writter.Common.IContentSource))]
  3. Use a common directory for the plugins (optional):

    path.JPG

And that is it… pretty simple!

String vs Type?

In a typical reflection-based addin framework, the contracts type is used to locate all the addins! This is fine if you have a static language (like C#), but what if you want to develop your addin using IronPython? Or any other dynamic language? MEF tries to accommodate these languages by moving away from the traditional type based identification to a simple string identifier!

Now we have some MEF-complaint plugins… how do we locate and use them?

Catalogs & Containers

A catalog is responsible for discovering extensions and the container coordinates creation and satisfies dependencies.

There are many ways of loading the composable parts… I will use the Import attribute:

[Import]
public IEnumerable<rudigrobler.writter.common.icontentsource> Extensions { get; set; }

One of the value propositions of MEF's attributed programming model is the ability to dynamically discover exports via catalogs. Catalogs allow applications to easily consume exports that have self-registered themselves via Export attributes. Below is a list the catalogs MEF provides by default:

ComposablePartCatalog catalog = new DirectoryPartCatalog("extensions", true);

MEF provides a few catalogs out of the box… We will be using the DirectoryPartCatalog! The DirectoryPartCatalog scans a specified directory (extension) for all the available parts.

CompositionContainer container = new CompositionContainer(catalog);
container.AddPart(this);
container.Compose();

The container is exactly what it sounds like! It's a container full of composable parts. The container is very similar to the IOC/DI containers like Unity. Calling Compose on the container matches all the exported parts (have) with Imported parts (needs).

Easy.jpg

And that is all that is required to make your application extensible! Here is the list of found plugins:

PluginsFound.jpg

MEF does an excellent job of making extensibility in software map to how we logically think about it: I have (export) you need (import).

Blogs

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

rudigrobler

South Africa South Africa
No Biography provided

Comments and Discussions

 
GeneralMy vote of 5 PinmemberSteveQ5630-Apr-13 2:32 
GeneralRefreshing Pinmemberkornakar8-Dec-08 0:13 
GeneralRe: Refreshing Pinmemberrudigrobler8-Dec-08 1:31 
Thank you Kornakar,
 
Any specific part you would like to be elaborated?
GeneralRe: Refreshing Pinmemberkornakar8-Dec-08 3:57 
GeneralRe: Refreshing PinmemberRoberto Collina8-Dec-08 4:16 
GeneralRe: Refreshing Pinmemberrudigrobler8-Dec-08 4:36 
GeneralRe: Refreshing PinmemberRoberto Collina8-Dec-08 8:56 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.141220.1 | Last Updated 8 Dec 2008
Article Copyright 2008 by rudigrobler
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid