3

System.Composition.Hosting.CompositionFailedException: The type 'ITranslatorMetaData' cannot be used as a metadata view. A metadata view must be a concrete class with a parameterless or dictionary constructor.

I'm just getting started with MEF in PCL (using the nuget Microsoft.Composition). I believe this is the "lightweight" MEF. In my implemented class I have

[Export(typeof(ITranslator))]
[ExportMetadata("Source", "Microsoft")]
[ExportMetadata("Order", "2")]

And I have an interface called ITranslatorMetaData

public interface ITranslatorMetaData
{
    [DefaultValue("Unknown")]
    string Source { get; }

    [DefaultValue(Int32.MaxValue)]
    int Order { get;  }
}

Finally, I try to import them using

    [ImportMany]
    private Lazy<ITranslator, ITranslatorMetaData>[] _translators { get; set; }

What am I doing wrong? Seems like this should just work.

Update I tried this to no avail.

[Export(typeof(ITranslator)),
    ExportMetadata("Source", "Microsoft"),
    ExportMetadata("Order", "2")]

Update 2 I did find an error, the Order should be an int not a string. But I still get the same error after specifying

[Export(typeof(ITranslator)),
    ExportMetadata("Source", "Microsoft"),
    ExportMetadata("Order", 2)]

Update 3 One proposed solution suggests I should not use an interface for the metadata, though the MEF examples in http://mef.codeplex.com/wikipage?title=Exports%20and%20Metadata&referringTitle=Guide clearly show using an interface for the metadata, rather than a concrete class.

tofutim
  • 22,664
  • 20
  • 87
  • 148
  • The exception cleanly conflicts with that example: have you tried running it? – David Mar 10 '15 at 18:17
  • Great scots you are right! – tofutim Mar 10 '15 at 18:59
  • found this http://stackoverflow.com/questions/13914256/strongly-typed-metadata-in-mef2-system-composition – tofutim Mar 10 '15 at 19:02
  • Never ever trust an example outright without poking it first. This is not the first time I've encountered such an issue (though admitedly one of the first times I've seen the sample doing something extra that the actual code isn't) – David Mar 10 '15 at 21:59

1 Answers1

5

As the exepction says, you must use a concrete class for the Metadata.

what this means is that interface and abstract class (EDIT: also static class) types are not allowed, since the MEF code would have no idea what to construct when pulling up the necessary Metadata.

Thus, if you change interface ITranslatorMetaData to class TranslatorMetaData like so

public class TranslatorMetaData
{
    [DefaultValue("Unknown")]
    string Source { get; set; }

    [DefaultValue(Int32.MaxValue)]
    int Order { get; set; }
}

The code is able to compile.

With regard to the constructor, a parameterless public constructor is assumed in the lack of other constructors, thus why the above code fits the necessary parameters. However, specifying a constructor with parameters will leave a class without a constructorless parameter, and result in the same error unless using the "dictionary" constructor mentioned in the error.

David
  • 10,458
  • 1
  • 28
  • 40
  • 1
    Is that a difference between regular and lightweight MEF? – tofutim Mar 10 '15 at 18:04
  • BTW, my previous code compiled too, the error happens when it tries to pull the imports. With your code change, System.ObjectDisposedException: Cannot access a disposed object. Object name: 'Root Lifetime Context'. – tofutim Mar 10 '15 at 18:07
  • Root lifetime context, would have to exmaine more of your code, possibly look into the exact library you're using. As for a difference, as far as I can tell no, the documentaion on MEF indicates that MEF constructs those MetaData objects based purely on import data, and since you're not specifying a concrete class the way you are for actual exports, it'll have no idea what objects to make – David Mar 10 '15 at 18:14
  • Somehow, it doesn't like having the TranslatorMetaData sent in that way. I'm getting the disposed object issue the moment I try to access any of the translators. – tofutim Mar 10 '15 at 18:35
  • No problems with private IEnumerable _translators { get; set; } though – tofutim Mar 10 '15 at 18:37
  • the problem is that I was disposing my container – tofutim Mar 10 '15 at 19:08
  • @Aravol "As for a difference, as far as I can tell no" There must be a difference - I've been using interfaces as metadata views for ages, and it's only now an issue that I'm porting some .NET Framework-based code to .NET Core (meaning I'm forced to rely on the "lightweight" version of MEF). – Tagc Oct 03 '16 at 13:55
  • Agreed with @Tagc, it was perfectly acceptable to use attribute classes without default constructors and import Lazy where TMetadata was an interface in MEF 1.0. It seems stupid to have to add default constructors everywhere where they don't make any sense. – Stephen Drew Feb 09 '18 at 18:16