Effin’ with MEF – Trying to actually understand what is going on this time.

By | June 9, 2014

I’ve used MEF before, as well as Prism, and any other number of IOC containers.  I’ve never bothered to actually understand what and how they work.  For this post (and any possible future posts), I want to take it really simple and slow.  I want to understand what MEF is doing (but not the behind-the-scenes, bare metal behind the scenes… maybe someday).

So, here is my first stab at a very simple MEF project that even I can understand.

First thing we have to do is reference the MEF assemblies.

01MefReferences

 

 

 

Create your module interface, and classes:

My module classes will have a simple DoIt() method that returns a string message.  The interface defines the contract for that method.

   1:   /// <summary>
   2:   /// MEF searches for classes that implement IDoIt
   3:   /// </summary>
   4:   public interface IDoIt
   5:   {
   6:       string DoIt();
   7:   }

 

Now we need to make some concrete classes that implement the interface IDoIt.

You’ll notice that we have to tell MEF that these classes are “Export”, which means that MEF knows that these classes should be considered for injection into our main class.

 1:  [Export(typeof(IDoIt))]
 2:  public class Di1 : IDoIt
 3:  {
 4:     public string DoIt()
 5:     {
 6:         return "Executed DoItModule1" + System.Environment.NewLine;
 7:     }
 8:  }
 9: 
 10: [Export(typeof(IDoIt))]
 11: public class Di2 : IDoIt
 12: {
 13:    public string DoIt()
 14:    {
 15:       return "Executed DoItModule2" + System.Environment.NewLine;
 16:    } 
 17: }

Now to set up MEF.

We have to create a container to hold our objects, and some startup code to tell MEF to do its thing.  The IEnumerable DoItModules ends up being a list modules that MEF found that are of type IDoIt.  MEF automatically creates the list of IDoIt modules when we call ComposeParts().

   1:   /// <summary>
   2:   /// This gets filled in by MEF automatically with IDoIt objects
   3:   /// found in this assembly
   4:   /// </summary>
   5:   [ImportMany(typeof(IDoIt))]
   6:   public IEnumerable<Lazy<IDoIt>> DoItModules { get; set; }
   7:   
   8:   /// <summary>
   9:   /// Load up our catalog of modules
  10:   /// </summary>
  11:   private void AvengersAssemble()
  12:   {
  13:       var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
  14:       var container = new CompositionContainer(catalog);
  15:       container.ComposeParts(this);
  16:   }

Here’s the whole thing:

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.ComponentModel.Composition;
   4:  using System.ComponentModel.Composition.Hosting;
   5:  using System.Linq;
   6:  using System.Reflection;
   7:  using System.Text;
   8:  using System.Threading.Tasks;
   9:  using System.Windows;
  10:  using System.Windows.Controls;
  11:  using System.Windows.Data;
  12:  using System.Windows.Documents;
  13:  using System.Windows.Input;
  14:  using System.Windows.Media;
  15:  using System.Windows.Media.Imaging;
  16:  using System.Windows.Navigation;
  17:  using System.Windows.Shapes;
  18:   
  19:  namespace MefTest
  20:  {
  21:      /// <summary>
  22:      /// Interaction logic for MainWindow.xaml
  23:      /// </summary>
  24:      public partial class MainWindow : Window
  25:      {
  26:          public MainWindow()
  27:          {
  28:              InitializeComponent();
  29:              AvengersAssemble();
  30:              this.Loaded += MainWindow_Loaded;
  31:          }
  32:   
  33:          /// <summary>
  34:          /// This gets filled in by MEF automatically with IDoIt objects
  35:          /// found in this assembly
  36:          /// </summary>
  37:          [ImportMany(typeof(IDoIt))]
  38:          public IEnumerable<Lazy<IDoIt>> DoItModules { get; set; }
  39:   
  40:          /// <summary>
  41:          /// Load up our catalog of modules
  42:          /// </summary>
  43:          private void AvengersAssemble()
  44:          {
  45:              var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
  46:              var container = new CompositionContainer(catalog);
  47:              container.ComposeParts(this);
  48:          }
  49:   
  50:          void MainWindow_Loaded(object sender, RoutedEventArgs e)
  51:          {
  52:              // making sure there are objects here
  53:              foreach (var module in this.DoItModules)
  54:              {
  55:                  info.Text += module.Value.DoIt();
  56:              }
  57:          }
  58:      }
  59:   
  60:      /// <summary>
  61:      /// MEF searches for classes that implement IDoIt
  62:      /// </summary>
  63:      public interface IDoIt
  64:      {
  65:          string DoIt();
  66:      }
  67:   
  68:      [Export(typeof(IDoIt))]
  69:      public class Di1 : IDoIt
  70:      {
  71:          public string DoIt()
  72:          {
  73:              return "Executed DoItModule1" + System.Environment.NewLine;
  74:          }
  75:      }
  76:   
  77:      [Export(typeof(IDoIt))]
  78:      public class Di2 : IDoIt
  79:      {
  80:          public string DoIt()
  81:          {
  82:              return "Executed DoItModule2" + System.Environment.NewLine;
  83:          }
  84:      }
  85:   
  86:   
  87:  }

 

The output of the project loads both DoIt modules, and prints out their DoIt() method to the user control.

02MEFOutputWindow

Leave a Reply

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