MEF with ImportMany and ExportMetadata
Asked Answered
H

2

11

I've just started playing around with Managed Extensibility framework. I've got a class that's exported and a import statement:

[Export(typeof(IMapViewModel))]
[ExportMetadata("ID",1)]
public class MapViewModel : ViewModelBase, IMapViewModel
{
}

    [ImportMany(typeof(IMapViewModel))]
    private IEnumerable<IMapViewModel> maps;

    private void InitMapView()
    {
        var catalog = new AggregateCatalog();
        catalog.Catalogs.Add(new AssemblyCatalog(typeof(ZoneDetailsViewModel).Assembly));
        CompositionContainer container = new CompositionContainer(catalog);

        container.ComposeParts(this);
        foreach (IMapViewModel item in maps)
        {
            MapView = (MapViewModel)item;                
        }
    }

This works just fine. The IEnumerable get the exported classes. No I try to change this to use the Lazy list and include the metadata so that I can filter out the class that i need (same export as before)

[ImportMany(typeof(IMapViewModel))]
    private IEnumerable<Lazy<IMapViewModel,IMapMetaData>> maps;

    private void InitMapView()
    {
        var catalog = new AggregateCatalog();
        catalog.Catalogs.Add(new AssemblyCatalog(typeof(ZoneDetailsViewModel).Assembly));
        CompositionContainer container = new CompositionContainer(catalog);

        container.ComposeParts(this);
        foreach (Lazy<IMapViewModel,IMapMetaData> item in maps)
        {
            MapView = (MapViewModel)item.Value;
        }            
    }

After this the Ienumerable has no elements. I suspect that i've made an obvious and stupid mistake somewhere..

Hoar answered 5/2, 2011 at 19:19 Comment(2)
What does your metadata interface look like?Bourn
Didn't know you could do an ImportMany including the metadata. nice!Agglutinogen
M
9

It is probably not matching because your metadata interface doesn't match the metadata on the export. To match the sample export you've shown, your metadata interface should look like this:

public interface IMapMetaData
{
    int ID { get; }
}
Mic answered 6/2, 2011 at 2:37 Comment(1)
I knew it was something stupid, just couldn't see it. In my interface the ID was string...Hoar
L
0

To add metadata to a class derived from a class to which InheritedExport has been applied, you must apply the same InheritedExport attribute also to the derived class. Otherwise, metdata applied to the derived class will be hidden and unavailable; metadata applied to the parent class will be replaced.

In other words, if you are using Lazy<T,TMetadata> to access applied metadata, and your imports are not being populated, it may mean you did not apply InheritedExport to all your derived classes. The part will still be exported due to the inherited InheritedExportAttribute, but the metadata will be replaced because that is how InheritedExport works.

If you instead apply Export instead of InheritedExport, you will end up with another instance of your part. For some unintuitive reason, Export injects a contract name derived from the class instead of what you specify and must be requested explicitly in your import statement.

Metadata is not additive. You get only the metadata applied to the class when the InheritedExport or Export attributes are applied.

Loaning answered 1/12, 2014 at 22:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.