MEF GetExports<T, TMetaDataView> returning nothing with AllowMultiple = True

attributes, c#, mef, metadata

Solution

It is known that MEF has some problems when dealing with `AllowMultiple = true`. For a complete explanation you could for instance look here, anyway it derives from the fact that the metadata are saved in a Dictionary where the values are arrays when AllowMultiple is true, and such a thing can't be mapped on your IMyInterfaceInfo.

This is the workaround I use. First of all your attribute should derive from Attribute, not from ExportAttribute:

[MetadataAttribute]
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
public class ExportMyInterfaceAttribute : Attribute, IMyInterfaceInfo
{
    public ExportMyInterfaceAttribute(Type someProperty1, double someProperty2, string someProperty3)

    {
        SomeProperty1 = someProperty1;
        SomeProperty2 = someProperty2;
        SomeProperty3 = someProperty3;
    }

    public Type SomeProperty1 { get; set; }
    public double SomeProperty2 { get; set; }
    public string SomeProperty3 { get; set; }
}

This means that the exported class should have 3 attributes, a standard export and your custom attributes:

[Export(typeof(IMyInterface))]
[ExportMyInterface(typeof(string), 0.1, "whoo data!")]
[ExportMyInterface(typeof(int), 0.4, "asdfasdf!!")]
public class DecoratedClass : IMyInterface

Then you have to define a view for the metadata which will be imported. This has to have a constructor that takes the IDictionary as parameter. Something like this:

public class MyInterfaceInfoView
{
    public IMyInterfaceInfo[] Infos { get; set; }

    public MyInterfaceInfoView(IDictionary<string, object> aDict)
    {
        Type[] p1 = aDict["SomeProperty1"] as Type[];
        double[] p2 = aDict["SomeProperty2"] as double[];
        string[] p3 = aDict["SomeProperty3"] as string[];

        Infos = new ExportMyInterfaceAttribute[p1.Length];
        for (int i = 0; i < Infos.Length; i++)
            Infos[i] = new ExportMyInterfaceAttribute(p1[i], p2[i], p3[i]);
    }
}

Now you should be able to successfully call

var myExports = CompositionContainer.GetExports<IMyInterface, MyInterfaceInfoView>();

Problem

I don't understand MEF very well, so hopefully this is a simple fix of how I think it works. I'm trying to use MEF to get some information about a class and how it should be used. I'm using the Metadata options to try to achieve this. My interfaces and attribute looks like this: ``` public interface IMyInterface { } public interface IMyInterfaceInfo { Type SomeProperty1 { get; } double SomeProperty2 { get; } string SomeProperty3 { get; } } [MetadataAttribute] [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] public class ExportMyInterfaceAttribute : ExportAttribute, IMyInterfaceInfo { public ExportMyInterfaceAttribute(Type someProperty1, double someProperty2, string someProperty3) : base(typeof(IMyInterface)) { SomeProperty1 = someProperty1; SomeProperty2 = someProperty2; SomeProperty3 = someProperty3; } public Type SomeProperty1 { get; set; } public double SomeProperty2 { get; set; } public string SomeProperty3 { get; set; } } ``` The class that is decorated with the attribute looks like this: ``` [ExportMyInterface(typeof(string), 0.1, "whoo data!")] [ExportMyInterface(typeof(int), 0.4, "asdfasdf!!")] public class DecoratedClass : IMyInterface { } ``` The method that is trying to use the import looks like this: ``` private void SomeFunction() { // CompositionContainer is an instance of CompositionContainer var myExports = CompositionContainer.GetExports<IMyInterface, IMyInterfaceInfo>(); } ``` In my case `myExports` is always empty. In my CompositionContainer, I have a Part in my catalog that has two `ExportDefinitions`, both with the following `ContractName`: "MyNamespace.IMyInterface". The `Metadata` is also loaded correctly per my exports. If I remove the `AllowMultiple` setter and only include one exported attribute, the `myExports` variable now has the single export with its loaded metadata. What am I doing wrong? EDIT: If I use weakly typed Metadata, my export is suddenly satisfied: ``` var myExports = CompositionContainer.GetExports<IMyInterface, IDictionary<string, object>>(); ``` Any ideas why?

Original source