This project has moved and is read-only. For the latest updates, please go here.

Declaring Imports

Composable Parts declare imports [System.ComponentModel.Composition.ImportAttribute] attribute. Similar to exports, there are several different methods namely through Fields, Properties and Constructor Parameters.

Property Imports

To import a value to a property, decorate the property with the [System.ComponentModel.Composition.ImportAttribute]. For example the snippet below imports an IMessageSender

  class Program
  {
    [Import]
    public IMessageSender MessageSender { get; set; }
  }
Class Program
    <Import()>
    Public Property MessageSender() As IMessageSender
End Class

Constructor Parameters

You can also specify imports through constructor parameters. This means that instead of adding properties for each import, you add parameters to a constructor for each import. To use this, follow the following steps.

1. Add a [System.ComponentModel.Composition.ImportingConstructorAttribute] attribute to the constructor that should be used by MEF.
2. Add parameters to the constructor for each import.

For example the code below imports a message sender in the constructor of the Program class.

  class Program
  {
    [ImportingConstructor]
    public Program(IMessageSender messageSender) 
    {
       ...
    }
  }
Class Program
    <ImportingConstructor()>
    Public Sub New(ByVal messageSender As IMessageSender) 
      ... 
    End Sub
End Class

Parameter imports

There are several different different ways to define imports on the constructor.

1. Implied import - By default the container will use the type of the parameter to identify the contract. For example in the code below, the IMessageSender contract will be used.

  class Program
  {
    [ImportingConstructor]
    public Program(IMessageSender messageSender) 
    {
    }
  }
Class Program
    <ImportingConstructor()>
    Public Sub New(ByVal messageSender As IMessageSender) 
    End Sub
End Class

2. Explicit import - If you want to specify the contract to be imported add an [System.ComponentModel.Composition.ImportAttribute] attribute to the parameter.

Field Imports

MEF also supports importing values directly to fields.

  class Program
  {
    [Import]
    private IMessageSender _messageSender;
  }
Class Program
    <Import()>
    Private _messageSender As IMessageSender
End Class

Note: note that importing or exporting private members (fields, properties and methods) while supported in full trust is likely to be problematic on medium/partial trust.

Optional imports

MEF allows you to specify that an import is optional. When you enable this, the container will provide an export if one is available otherwise it will set the import to Default(T). To make an import optional, set AllowDefault=true on the import as below.

[Export]
public class OrderController {
  private ILogger _logger;

  [ImportingConstructor]
  public OrderController([Import(AllowDefault=true)] ILogger logger) {
    if(logger == null)
      logger = new DefaultLogger();
    _logger = logger;
  }
}
<Export()>
Public Class OrderController
    Private _logger As ILogger

    <ImportingConstructor()>
    Public Sub New(<Import(AllowDefault:=True)> ByVal logger As ILogger) 
        If logger Is Nothing Then
            logger = New DefaultLogger()
        End If
        _logger = logger
    End Sub
End Class

OrderController optionally imports a logger. If the logger is not present, it will set it's private _logger to a new DefaultLogger instance otherwise it will use the imported logger.

Importing collections

In addition to single imports, you can import collections with the ImportMany attribute. This means that all instances of the specific contract will be imported from the container.

MEF parts can also support recomposition. This means that as new exports become available in the container, collections are automatically updated with the new set. For example below the Notifier class imports a collection of IMessageSender. This means if there are 3 exports of IMessageSender available in the container, they will be pushed in to the Senders property during compositon.

 public class Notifier 
 {
    [ImportMany(AllowRecomposition=true)]
    public IEnumerable<IMessageSender> Senders {get; set;}

    public void Notify(string message) 
    {
      foreach(IMessageSender sender in Senders)
      {
        sender.Send(message);
      }
    } 
  }
Public Class Notifier
    <ImportMany(AllowRecomposition:=True)> 
    Public Property Senders() As IEnumerable(Of IMessageSender) 

    Public Sub Notify(ByVal message As String) 
        For Each sender As IMessageSender In Senders
            sender.Send(message) 
        Next sender
    End Sub
End Class

IPartImportsSatisfiedNotification

In some situations it may be important for your class to be notified when MEF is done with the import process for your class instance. If that's the case implement the [System.ComponentModel.Composition.IPartImportsSatisfiedNotification] interface. This interface has only a single method: OnImportsSatisfied, which is called when all imports that could be satisfied have been satisfied.

 public class Program : IPartImportsSatisfiedNotification
 {
    [ImportMany]
    public IEnumerable<IMessageSender> Senders {get; set;}

    public void OnImportsSatisfied() 
    {
      // when this is called, all imports that could be satisfied have been satisfied.
    } 
  }
Public Class Program
    Implements IPartImportsSatisfiedNotification
    <ImportMany()>
    Public Property Senders() As IEnumerable(Of IMessageSender) 

    Public Sub OnImportsSatisfied() Implements IPartImportsSatisfiedNotification.OnImportsSatisfied
        ' when this is called, all imports that could be satisfied have been satisfied. 
    End Sub
End Class

Last edited Aug 9, 2010 at 6:16 PM by haveriss, version 17

Comments

nodirt Jun 13, 2012 at 1:30 PM 
Hi. There is a typo "different different" in "Parameter imports" section

threeputt Aug 25, 2010 at 10:16 PM 
This sentence, from the Optional Import section of this page, could use a little more explanation and it would be nice if that discussion also was reflected in the coding example. "When [optional imports], the container will provide an export if one is available otherwise it will set the import to Default(T). " The coding example did not show an example of Default(T) unless the conditional code that determines if the import is null is what was meant by "Default(T)".

RichardFine Jun 7, 2010 at 3:58 PM 
When does resolution of [Import]-tagged fields happen, relative to the constructor being called? I'd originally assumed before, but now it seems like they're done after. As such it might be worth adding a note about this to underline that the [ImportingConstructor] stuff isn't just available to bring stuff into the constructor, it's actually /necessary/, because the other [Import]s won't be ready yet.

cesnek Apr 2, 2010 at 2:13 PM 
Any support on [ImportMany] public IDictionary<metadata, object> ?

gblock Mar 27, 2010 at 11:28 PM 
@Nathan ExportCollection is now gone. Instead you use collection of Lazy<T> / Lazy<T,M>. We also support arrays which is less verbose...ie. Lazy<T>[].

bartelink Feb 25, 2010 at 10:43 AM 
Dear Mr LazyWeb: This is one of the top two hits for ImportingConstructor example. http://stackoverflow.com/questions/2008133/mef-constructor-injection is the other and solved my issue (wanted to pass a context param). If you feel an example (of an Import attribute on a constructor arg) makes sense in here, it'd be nice to have it (but I ahvent looked at this wiki in its entirity so dont feel qualified to edit.).

nblumhardt Jul 7, 2009 at 4:42 PM 
Thanks for the corrections, fixed now.

superlloyd Jun 25, 2009 at 3:45 PM 
I am using Preview 5
INotifyImportSatisfaction is missing

but I found IPartImportsSatisfiedNotification
which seems to be its replacement

NathanRidley Apr 28, 2009 at 1:13 PM 
Working with Preview 5 for this comment. There is an inconsistency between a constructor import and a property import when importing a collection of parts. In a property you have to use ExportCollection<T> but in the constructor you have to use Export<T>[]. Why the ExportCollection for one and Export[] for the other?