19 November 2008 AddIns, HowTo, MEF, Plugins, System.AddIn Robert Muehsig

In nearly every application you can install and use plugins (Firefox, Outlook, IE...). With .NET 4.0 you get a new feature to create extensible applications called "Managed Extensibility Framework" in short "MEF". You can today play with a preview of this upcoming framework.
Microsoft itself will use it in Visual Studio 2010 (take a look at the PDC Keynote from Scott Guthrie). A very nice demo of MEF was in the PDC session of Scott Hanselman and his "BabySmash". But there are a lot of other great MEF PDC Sessions.

Addins? .NET? System.Addin? 
The "System.AddIn" Namespace was introduced in .NET 3.5, but it was very hard to create addins. But MEF and System.AddIn should play well together.

What´s needed to play with MEF?
Everything you needed to start you can download at the Codeplex Site. Just download the newest release and copy the 2 DLLs in your project directory (Disclaimer- it´s still in development, everything might be changed until the release).

Hello World! Hallo Welt! Hello MEF! - Preparation

Projectstructure:

image

We have a simple service interface called "IHelloService":

    public interface IHelloService
    {
        string GetHelloMessage();
    }

In the HelloMEF.English / German Project we have the following code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using HelloMEF.App;
using System.ComponentModel.Composition;

namespace HelloMEF.English
{
    [Export(typeof(IHelloService))]
    public class EnglishHelloService : IHelloService
    {
        public string GetHelloMessage()
        {
            return "Hello World!";
        }
    }
}


Important for MEF is the "Export" attribut from the "System.ComponentModel.Composite" (MEF) Namespace.


Export means: This is a "IHelloService" plugin.

Both projects need only the reference to the HelloMEF.App because of the IHelloService interface.
The HelloMEF.App doesn´t know anything about these projects!

Plugin dictionary
Your application needs to know where plugins are placed, that´s why we create a "PlugIns" dictionary:

image

HelloMEF.App - HelloProgram:

    public class HelloProgram
    {
        [Import(typeof(IHelloService))]
        public List<IHelloService> Services { get; set; }

        public HelloProgram()
        {
	... 
        }

        public void WriteHelloGreetings()
        {
            Console.WriteLine();
            Console.WriteLine("Writing Greetings...");

            foreach (IHelloService srv in Services)
            {
                Console.WriteLine(srv.GetHelloMessage());
            }

            Console.WriteLine("... powered by MEF");
        }
    }

Inside the "HelloProgram" class is a "IHelloServices" list, which is decorated with the "Import" attribute from the MEF namespace.
Import means: I took everything of type IHelloService.

The "WriteHelloGreeting" just iterate over the services list and write the message to the console.

HelloMEF.App - search & found plugins:

        public HelloProgram()
        {
            this.Services = new List<IHelloService>();

            if (!Directory.Exists("PlugIns"))
            {
                Directory.CreateDirectory("PlugIns");
            }

            AggregatingComposablePartCatalog catalog = new AggregatingComposablePartCatalog();
            catalog.Catalogs.Add(new AttributedAssemblyPartCatalog(Assembly.GetExecutingAssembly()));
            catalog.Catalogs.Add(new DirectoryPartCatalog("PlugIns"));
            
            CompositionContainer container = new CompositionContainer(catalog.CreateResolver());
            container.AddPart(this);
            container.Compose();
        }

At first we search for the "PluginIns" directory and create it if it it´s necessary. Now - pure MEF action:
Plugins are manged with parts and catalogs. We tell our catalog to search for plugins in this assembly:

            catalog.Catalogs.Add(new AttributedAssemblyPartCatalog(Assembly.GetExecutingAssembly()));

... and to look at this directory:

            catalog.Catalogs.Add(new DirectoryPartCatalog("PlugIns"));

We can also observe the directory, to add plugins while the application is running:

image

Through the container we tell MEF that here is a plugin interface (the list with the import attribute) and start the "compose" process.

HelloMEF.App - Plugins inside the assembly:

namespace HelloMEF.App
{
    public class HelloProgram
    {
	...
    }

    [Export(typeof(IHelloService))]
    public class MEFHelloService : IHelloService
    {
	...
    }

}

The plugins could be placed inside the assembly. MEF find these plugins through this catalog: "AttributeAssemblyPartCatalog"

The result:

image

 [ Download Source Code ]


Written by Robert Muehsig

Software Developer - from Saxony, Germany - working on primedocs.io. Microsoft MVP & Web Geek.
Other Projects: KnowYourStack.com | ExpensiveMeeting | EinKofferVollerReisen.de