Archive for February, 2011

MEF–Managed Extensibility Framework

February 16, 2011

A work colleague and I sat in on a live meeting of Chandan Banerjee from Microsoft talk about MEF.

Mainly work off the “O” in the S.O.L.I.D principle that “software entities … should be open for extension, but closed for modification”.

MEF provides the ability at runtime to resolve class members \ retrieve instances of objects at runtime via attributes.

There is a Host that will consume annotated with the [Import] attribute. In a typical implementation there will be a class library that provides the class to be consumed via the [Export] attribute and maybe a library containing the interface that the consumable classes derive off.

The Host (unfortunately) needs to have some code to load up the catalogue and containers and register itself only after that do the import and exports get matched up.

A catalogue can be a type catalogue, an assembly catalogue, a directory catalogue or a combination of the three. A catalogue is made up of one or more containers, where a container is made up of one or more parts. A part is a class that is marked with the [Export] attribute and matched with a member in the Host application that is marked with the [Import] attribute.

So in the sample below the part is the EmailSender. The Host is consuming the IMessageSender Interface declared in the same assembly the consumption is done via the [Import] on the MessageSender member variable of the Program class. The code to load up the catalogue is in the Compose method of the program class. The compose method loads up the currently executing assembly creates a container based on that then registers itself. The magic occurs in the call to ComposeParts where the Exports and Imports are matched up base on interface name.

The example is a scenario where the Host, the Interface and the part are all in the same assembly. You can just as easily put the host, Interface declaration and Part in their own assembies. If this were the case then the compose method would have to be modified to load the appropriate parts assembly.

   1: using System.ComponentModel.Composition;

   2: using System.ComponentModel.Composition.Hosting;

   3: using System.Reflection;

   4: using System;

   5:  

   6: public class Program

   7: {

   8:   [Import]

   9:   public IMessageSender MessageSender { get; set; }

  10:  

  11:   public static void Main(string[] args)

  12:   {

  13:     Program p = new Program();

  14:     p.Run();

  15:   }

  16:  

  17:   public void Run()

  18:   {

  19:     Compose();

  20:     MessageSender.Send("Message Sent");

  21:   }

  22:  

  23:   private void Compose()

  24:   {

  25:     AssemblyCatalog catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());

  26:     var container = new CompositionContainer(catalog);

  27:     container.ComposeParts(this);

  28:   }

  29: }

  30:  

  31: public interface IMessageSender

  32: {

  33:   void Send(string message);

  34: }

  35:  

  36: [Export(typeof(IMessageSender))]

  37: public class EmailSender : IMessageSender

  38: {

  39:   public void Send(string message)

  40:   {

  41:     Console.WriteLine(message);

  42:   }

  43: }

Advertisements