Search code examples
c#wpfmef

MEF - [ImportMany] using ExportFactory<T> in WPF - .NET 4.0


I have some part imports that I need to create multiple instances of. By searching around I decided I needed to use the ExportFactory class. Unfortunately, the ExportFactory class is not available in WPF by default, but luckily Glenn Block has ported the code.

Originally, I was specifying the type when importing:

[ImportMany(typeof(IMyModule))]
public IEnumerable<Lazy<IMyModule, IMyModuleMetadata>> Modules { get; set; }

I also created an export attribute:

[MetadataAttribute]
[AttributeUsage(AttributeTargets.Class, AllowMultiple=false)]
public class ExportMyModuleMetadata : ExportAttribute, IMyModuleMetadata
{
    public ExportMyModuleMetadata(string category, string name)
        : base(typeof(IMyModuleData))
    {
        Category = category;
        Name = name;
    }
    public string Category { get; set; }
    public string Name { get; set; }
}

My export looks like this:

[ExportMyModuleMetadata("Standard","Post Processor")]
[PartCreationPolicy(CreationPolicy.NonShared)]
public class Module1 : IMyModuleData

The above import worked fine. But once I changed Lazy<T,T> to ExportFactory<T,T> I started getting an error during composition.

[ImportMany(typeof(IMyModule))]
public IEnumerable<ExportFactory<IMyModule, IMyModuleMetadata>> Modules { get; set; }

The error message I got was:

The export 'Module1 (ContractName="IMyModule")' is not assignable to type
'System.ComponentModel.Composition.ExportFactory`

I saw somewhere (that I can't find the link for right now) that specifying the Type in the ImportMany attribute is the problem. I figured I could do without it so I removed the type from the ImportMany.

[ImportMany()]
public IEnumerable<Lazy<IMyModule, IMyModuleMetadata>> Modules { get; set; }

This import still worked when using Lazy<T,T>, but once I changed it to ExportFactory<T,T>, I no longer import anything. I didn't get an error anymore but nothing gets imported.

Does anyone know how to properly use ImportMany with ExportFactory<T,T> for WPF?

Update:

With Wes's tip about adding an ExportFactoryProvider(), I got the ExportFactory<T,T> working in .NET 4! Below is the updated composition code.

var ep = new ExportFactoryProvider();

//Looks for modules in main assembly and scans folder of DLLs for modules.
var moduleCatalog = new AggregateCatalog(
    new AssemblyCatalog(runningApp),
    new DirectoryCatalog(".", "*.dll"));
var container = new CompositionContainer(moduleCatalog, ep);
ep.SourceProvider = container;
var Modules = new Modules();
container.ComposeParts(Modules);

I also found a discussion on this at MEF Codeplex site that talks a little more about this.


Solution

  • In general on .NET 4.0 ExportFactory isn't supported out of the box. ExportFactory is special type that the container (or a custom export provider) knows about and treats specially and based on the error message you have received it doesn't look like this container knows anything special about ExportFactory because it is trying to cast it to IMyModule.

    Have a look at Glen's tests for ExportFactory did you add a Microsoft.ComponentModel.Composition.Hosting.ExportFactoryProvider to your container?

    Also note that if you have an option to switch to .NET 4.5, ExportFactory is supported out of the box.