1
votes

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

2

2 Answers

1
votes

ImportingConstructor

The way you Import/Export parts in your sample code, if MyMainClass is getting composed, the implicit parameterless constructor is called, then an instance of MySimpleCalculator is assigned to the calculator field.

Now let's say you rather want to have a readonly field/a get-only property, or otherwise need to access the ICalculator in the constructor, you need to have it passed to the constructor rather than later on assigned to the field:

public interface ICalculator
{
    bool Quack { get; }
}

[Export(typeof(ICalculator))]
public class MySimpleCalculator : ICalculator
{
    public bool Quack => true;
}

[Export]
public class MyMainClass
{
    public ICalculator Calculator { get; }
    public string Blah { get; }

    [ImportingConstructor]
    public MyMainClass(ICalculator calculator)
    {
        Calculator = calculator; // assign readonly property
        Blah = calculator.Quack ? "Foo" : "Bar"; // do something based on calculator
    }
}

Now the argument(s) to the constructor are implicitly imported and satisfied with a corresponding export.

AllowDefault

If you [Import] something, that something must be available or composition fails.

If you [Import(AllowDefault = true)] something, composition wont' fail if there's no corresponding export, but you get null/false/0 as imported value.

BTW: sorry for being slightly sarcastic, but the answer could as well be RTFM.

0
votes

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;
}
}