Search code examples
c#.netmef

Difference between Import and ImportingConstructor attributes in MEF with proper examples?


Can anyone help me with Import and ImportingConstructor attributes in MEF with relevant examples and when to use ? what is the use of [Import(AllowDefault = true)] ?

From my understanding of MEF:

Export attribute is defined on Class of type T where T is interface and to create a instance of that class Import attribute should be defined on the reference variable like below

[Export(typeof(ICalculator))]
class MySimpleCalculator : ICalculator
{
     // Implement the interface
}

class MyMainClass
{
   // MEF engine creates an instance as Export attribute is defined
   // on MySimpleCalculator

    [Import(typeof(ICalculator))]
    public ICalculator calculator;
}

If Multiple Exports of type T are defined in a given assembly then we can use ImportMany attribute.

So now can anyone explain when to use Import and ImportingConstructor and also AllowDefault attribute in the constructor ?

It would be great if someone can explain with better examples.

Any help would be appreciated. Thanks


Solution

  • There are three basic parts to MEF in your application. If we use a laptop analogy, we can visualize these three parts as the USB port on the laptop, an external hard drive with a USB connector, and the hand that plugs the USB connector into the port. In MEF terms, the port is defined as an [Import] statement. This statement is placed above a property to tell the system that something gets plugged in here. The USB cable is defined as an [Export] statement. This statement is placed above a class, method, or property to indicate that this is an item to be plugged in somewhere. An application could (and probably will) have a lot of these exports and imports. The job of the third piece is to figure out which ports we have and thus which cables we need to plug into them. This is the job of the CompositionContainer. It acts like the hand, plugging in the cables that match up to the appropriate ports. Those cables that don’t match up with a port are ignored.

    [ImportMany] //  It allows us to import zero or more Exported items that match. 
    private IEnumerable<Lazy<IProvider, IMetaData>> _Providers;
    
    [Export] // This tag is required if you want to create an instance in the child class
    private readonly IFacade _iFacade;
    
    #region [ MEF Loading ]
    
    private void LoadPlugin()
    {
    var pluginsDirectoryPath = ConfigurationReader.PluginsDirectoryPath;
    if (System.IO.Path.IsPathRooted(pluginsDirectoryPath) == false)
    pluginsDirectoryPath =
    
    System.IO.Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, pluginsDirectoryPath);
    
    pluginsDirectoryPath = System.IO.Path.GetFullPath(pluginsDirectoryPath);
    if (System.IO.Directory.Exists(pluginsDirectoryPath) == false)
    {
    throw new CriticalException(
    "The plugins directory path is not defined. Add Plugins parameter to configuration file.");
    }
    
    //An aggregate catalog that combines multiple catalogs
    var catalog = new AggregateCatalog();
    // Plgins only load from plugins directory for now
    catalog.Catalogs.Add(new DirectoryCatalog(pluginsDirectoryPath));
    
    //Create the CompositionContainer with the parts in the catalog
    var container = new CompositionContainer(catalog);
    
    //Fill the imports of this object
    try
    {
    container.ComposeParts(this);
    }
    catch (CompositionException compositionException)
    {
    throw new CriticalException("Unable to load authentication plugins", compositionException);
    }
    }
    #endregion [ MEF Loading ]
    

    All the above code is in the same class, now we need to create an instance in the constructor of that class.

    public ABCFacade(Ifacade iFacade)
    {
    LoadPlugin();
    _iFacade = iFacade; // Make sure the class instance that you want to create in the child class must have a [Export] tag, like we did in above.
    }
    
    
    Export(typeof(IProvider))]
    [ExportMetadata("ProviderName", "ABC")]
    public class Plugin : IProvider
    {
    private readonly IFacade _iFacade;
    [ImportingConstructor] // This tag will override the constructor.
    public Plugin(IFacade iFacade)
    {
      _iFacade = iFacade;
    }
    }