This project has moved. For the latest updates, please go here.

Hosting MEF in an application

Hosting MEF in an application involves creating an instance of the CompositionContainer, adding Composable Parts to it, including the application host itself and then composing.

Below are the steps involved with hosting.

1. Create a host class. In the sample below we are using a console application, so the host is the Program class.
2. Add a reference to the System.ComponentModel.Composition assembly.
3. Add the following using statement: using System.ComponentModel.Composition;
4. Add a Compose() method which creates an instance of the container and composes the host.
5. Add a Run() method which calls Compose();
6. In the Main() method instantiate the host class.

Note: For an ASP.NET or WPF application the host class is instantiated by the runtime making this step unnecessary.

The code snippet below indicates how the code should look

  using System.ComponentModel.Composition;
  using System.ComponentModel.Composition.Hosting;
  using System.Reflection;
  using System;

  public class Program
  {
    public static void Main(string[] args)
    {
      Program p = new Program();
      p.Run();
    }

    public void Run()
    {
      Compose();
    }

    private void Compose()
    {
      var container = new CompositionContainer();
      container.ComposeParts(this);
    }
  }

  Imports System.ComponentModel.Composition
  Imports System.ComponentModel.Composition.Hosting
  Imports System.Reflection
  Imports System

  Public Class Program
	Public Shared Sub Main(ByVal args() As String) 
	  Dim p As New Program()
	  p.Run()
	End Sub

	Public Sub Run()
	  Compose()
	End Sub

	Private Sub Compose()
	  Dim container = New CompositionContainer()
	  container.ComposeParts(Me) 
	End Sub
  End Class

7. Define one or more exports which the host will import. In the code below we've defined an IMessageSender interface. We've also defined an EmailSender Composable Part that exports an IMessageSender which it declares through the [System.ComponentModel.Composition.Export] attribute.

  public interface IMessageSender
  {
    void Send(string message);
  }

  [Export(typeof(IMessageSender))]
  public class EmailSender : IMessageSender
  {
    public void Send(string message)
    {
      Console.WriteLine(message);
    }
  }

Public Interface IMessageSender
    Sub Send(ByVal message As String) 
End Interface

<Export(GetType(IMessageSender))> 
Public Class EmailSender
    Implements IMessageSender
    Public Sub Send(ByVal message As String) Implements IMessageSender.Send
        Console.WriteLine(message) 
    End Sub
End Class

8. Add properties to the host class for each import which are decorated with the [System.ComponentModel.Composition.Import] attribute. For example below is an import for IMessageSender that is added to the Program class.

  [Import]
  public IMessageSender MessageSender { get; set; }

  <Import()>
  Public Property MessageSender() As IMessageSender

9. Add parts to the container. In MEF, there are several ways in which to do this. One way is by directly adding existing Composable Part instances, while a second, more common approach is through the use of catalogs, which we will mention after the section below.

Adding parts directly to the container

In the Compose() method manually add each Composable Part by using the ComposeParts() extension method. In the example below, an instance of the EmailSender added to the container along with the current instance of the Program class which imports it.

  private void Compose()
  {
    var container = new CompositionContainer();
    container.ComposeParts(this, new EmailSender());
  }

  Private Sub Compose()
      Dim container = New CompositionContainer()
      container.ComposeParts(Me, New EmailSender())
  End Sub

Adding to the container using an AssemblyCatalog

By using the catalog, the container handles creating parts automatically rather than them having to be added explicitly. To do this, create a catalog in the Compose() method. Next create a resolver off of the catalog and pass it to the container's constructor.

In the example below an AssemblyCatalog is created with the executing assembly passed into the constructor. We're not adding an instance of EmailSender as it it will be discovered in the catalog that was passed for the current assembly.

  private void Compose()
  {
    var catalog = new AssemblyCatalog(System.Reflection.Assembly.GetExecutingAssembly());
    var container = new CompositionContainer(catalog);
    container.ComposeParts(this);
  }

  Private Sub Compose()
     Dim catalog = New AssemblyCatalog(System.Reflection.Assembly.GetExecutingAssembly())
     Dim container = New CompositionContainer(catalog) 
     container.ComposeParts(Me) 
  End Sub

After following each of the above steps, the code should look as shown below.

  using System.ComponentModel.Composition;
  using System.ComponentModel.Composition.Hosting;
  using System.Reflection;
  using System;

  public class Program
  {
    [Import]
    public IMessageSender MessageSender { get; set; }

    public static void Main(string[] args)
    {
      Program p = new Program();
      p.Run();
    }

    public void Run()
    {
      Compose();
      MessageSender.Send("Message Sent");
    }

    private void Compose()
    {
      AssemblyCatalog catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
      var container = new CompositionContainer(catalog);
      container.ComposeParts(this);
    }
  }

  public interface IMessageSender
  {
    void Send(string message);
  }

  [Export(typeof(IMessageSender))]
  public class EmailSender : IMessageSender
  {
    public void Send(string message)
    {
      Console.WriteLine(message);
    }
  }

Imports System.ComponentModel.Composition
Imports System.ComponentModel.Composition.Hosting
Imports System.Reflection
Imports System

Public Class Program
    <Import()>
    Public Property MessageSender() As IMessageSender

    Public Shared Sub Main(ByVal args() As String) 
        Dim p As New Program()
        p.Run()
    End Sub

    Public Sub Run()
        Compose()
        MessageSender.Send("Message Sent")
    End Sub

    Private Sub Compose()
        Dim catalog As New AssemblyCatalog(System.Reflection.Assembly.GetExecutingAssembly())
        Dim container = New CompositionContainer(catalog) 
        container.ComposeParts(Me) 
    End Sub
End Class

Public Interface IMessageSender
    Sub Send(ByVal message As String) 
End Interface

<Export(GetType(IMessageSender))> 
Public Class EmailSender
    Implements IMessageSender
    Public Sub Send(ByVal message As String) Implements IMessageSender.Send
        Console.WriteLine(message) 
    End Sub
End Class


When the above code is compiled and executed, the application will be composed with its IMessageSender import. The Send() method will then be called which will output "Message Sent" on the console.

Note: For more advanced scenarios around hosting, see this post: uri:http://codebetter.com/blogs/glenn.block/archive/2010/01/15/hosting-mef-within-your-applications.aspx

Last edited Aug 9, 2010 at 5:41 PM by haveriss, version 49

Comments

playhere Oct 14, 2011 at 2:27 AM 
It's great for newbie as me!

hooke Sep 11, 2011 at 4:12 AM 
good, very good

s0ftimage Apr 29, 2011 at 6:06 PM 
Excellent composition example with everything in a single file.

DustinDavis Jan 5, 2011 at 5:01 PM 
For those who keep saying that a DI-Framework can do this: realize that this is for plug-ins and plug-in discovery. Not for DI or IoC. Of course, based on this example I would stick to writing my own plug-in framework. Seems like too much work to use this MEF; having to decorate exports with meta data. The consuming application would need to know what to look for ahead of time. Do you think that Winamp or Photoshop know anything about plug-ins I would write for them? No. Again, this statement is based on this example. Also, I don't see the point in sharing plug-ins between applications. They would need to be similar contexts unless it was a seriously generic plug-in like sending email. I just can't see the benefit over using my own framework.

bhtbed Aug 6, 2010 at 9:06 AM 
It's not that good.

ajay555 Jun 2, 2010 at 7:41 PM 
I got some comments to post the MEF Example II source code in VS 2010 and .NET 4.0. Well I am happy to say that its now available for download.

http://ajay555.wordpress.com/2010/06/03/mef-example-part-ii-vs2010-and-net-4-0/

hyffrank May 28, 2010 at 2:55 AM 
What this sample does looks just like what DI framework is doing.
The only difference is : in DI framework, you ask the container to create the composed object before using it; and in this MEF sample, you passed the object itself into the container and asked the container to compose the dependencies for you.
So what's the benefits of this approach?

henrikweimenhog May 18, 2010 at 11:19 AM 
A question:
If I have 3 parts which imports a fourth part, do I call composeParts 3 times?
What if a part imports multiple parts? Do I call it once for every import?
Slightly confusing, I thought it was easier before when I just used .addPart(object) for every part and baked them all together with compose()

ajay555 Apr 22, 2010 at 5:44 AM 
Migrated my blog to WordPress. You can find the MEF example on below mentioned URL:
Part I: http://ajay555.wordpress.com/2009/11/30/managed-extensibility-framework-mef-example/
Part II: http://ajay555.wordpress.com/2010/04/10/managed-extensibility-framework-mef-example-%E2%80%93-part-ii/

Happy Blogging !!!

ajay555 Apr 10, 2010 at 12:22 PM 
One of the comment posted in my earlier example of MEF was what if we have two implementations of the same interface and we need to decide at run time which implementation to use. I have posted another blog which gives the example of usage of ExportMetadata for handing this scenario.

http://ppsinfo.blogspot.com/2010/04/managed-extensibility-framework-mef.html

ajay555 Dec 2, 2009 at 9:41 AM 
I wanted to see an example where Contracts are defined in one project, multiple implementations are defined in other projects and a separate consumer projects which uses contract and has extension folder where implementation dll's can be simply copied and is available to the consumer application without any code changes. So I tried writing a simple Hello World kind of application and posted at my blog. Hope you might find it useful. I have also posted the source code (in C#).

http://ppsinfo.blogspot.com/2009/11/managed-extensibility-framework-mef.html

DenisVuyka Oct 19, 2009 at 8:30 PM 
Actually in my opinion the decoupling of core functionality and extra one (extension methods) is cool until both share the same namespace. It is not obvious why there are some methods missing in Catalog until you declare "System.Component.Model.Composition" namespace. This means that documentation and samples should always highlight that two namespaces have to be declared in order to reproduce samples. Thanks, Denis.

nblumhardt Jul 30, 2009 at 11:59 PM 
Hi Justin,

The method signature I've got is:

public static void ComposeParts(this CompositionContainer container, params object[] attributedParts)

Is this the same method you're seeing? If not, do you have the Preview 6 release?

Thanks,

Nick

justinc Jul 24, 2009 at 5:52 PM 
container.ComposeParts(this);

No longer compiles with the latest sample. It appears that that method accepts an abstract class as a parameter, of which all derived types are internal. This makes things very confusing. Can we get an update to these samples?

nblumhardt Jul 9, 2009 at 8:48 PM 
Thanks everyone for pointing out the things that needed updating. I've run though and made the changes.

Nick

dhaneshkk May 21, 2009 at 6:57 PM 
to run on preview 5
Add following code lines
at top
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Reflection;
using System;
and
find and replace "AttributedAssemblyPartCatalog" with "AssemblyCatalog"

magr May 17, 2009 at 8:54 PM 
This code does not seem to compile with Preview 5
batch.AddPart(this);

hrabia May 6, 2009 at 8:47 AM 
hmm, I hope the quality of the framework is better ;) -> batch.Compose(batch); should be container.Compose(batch);

philipf Mar 29, 2009 at 9:48 AM 
In MEF preview 4 release, I had to update the using statement to using System.ComponentModel.Composition.Hosting;

mvargas Mar 10, 2009 at 11:53 PM 
Hi Glenn, if I'm not mistaken, you mentioned on Scott Hanselman's podcast that the DirectoryCatalog won't exist in the final release. Is this correct? If so, it seems we'll be pretty short on catalog types. Will we be expected to implement our own catalog types?

fir3pho3nixx Feb 26, 2009 at 2:23 PM 
I would like to know a few things:

1. Why do I have to attribute my constructor with with the [ImportingConstructor] attribute if I am using [Import] parameters as arguments? Wouldn't it make sense just to check if the param count for the constructor > 0 and make the behaviour implicit without having to declare the attribute?

2. What was the idea behind the CompositionBatch? It feels very clunky to have to instantiate it when adding parts. There is no configuration that drives this either. Can't we have it as an instance on the container already? Alot of time will be spent writing code specifying the parts for the compositions, given that we have attributed everything already could this not be implicitly be discovered given that the specialised catalog is passed into the constructor of the container?

3. Once you app is built, is their a cool way of discovering the contracts for all extension points? The more visible these are the better right?

ManishBHarti Feb 16, 2009 at 2:28 PM 
Detail documentation and training Vidio is required. Example is too simple need other samples to get better understanding.

KeepItSimple Feb 6, 2009 at 12:37 AM 
5th code snippet, last line should read
container.Compose(batch);

camerons Jan 29, 2009 at 10:40 PM 
With Preview4 AttributedAssemblyPartCatalog is now AssemblyCatalog

gblock Jan 29, 2009 at 7:15 AM 
Thans andreir, we just fixed up the snippets.

andreir Dec 1, 2008 at 2:49 PM 
in the first code snippet the last line :

contianer.Compose();

should read

container.Compose();

Slight misspelling but I felt the need to report it.

austegard Oct 3, 2008 at 6:48 PM 
not to mention that the example code has typos (step 6). Please make sure all sample code compiles before copying and pasting.

glennen Sep 6, 2008 at 3:22 PM 
Kind of misleading/too simple example as it only shows what any DI-framework could do..