I'm trying to port a collection of .NET Framework-based applications to .NET Core, and as part of this process I need to switch from using MEF1 to MEF2. I've been having a lot of difficulty wrapping my head around issues relating to MEF2 (though I've found this post really helpful), but I've recently stumbled across the reason behind one of them I've been having.
In particular, I have a number of classes that export metadata using a custom ExportAttribute
and I would like to import them all in another class and filter them based on this metadata. This was all working fine in MEF1 but in MEF2 I ran up against problems such as "Export metadata for x is missing and no default value was supplied.".
More specifically, I annotate my exported classes like below:
[Export(typeof(IClientRequestProcessor<RelaySystemModel>))]
[TargetDevice("<<Foo>>")]
internal class RelaySystemClientRequestProcessor : IClientRequestProcessor<RelaySystemModel>
{
}
Then elsewhere, I will try to import them like this:
[ImportMany]
public IEnumerable<ExportFactory<IClientRequestProcessor<RelaySystemModel>, DeviceSpecific>> RelayRequestProcessors { private get; set; }
And then, on satisfaction of imports, attempt to filter them by metadata:
private static IEnumerable<ExportFactory<T, DeviceSpecific>> FilterForFoo<T>(IEnumerable<ExportFactory<T, DeviceSpecific>> items)
{
return from it in items where it.Metadata.DeviceId == "<<Foo>>" select it;
}
Where TargetDeviceAttribute
is defined as follows:
[MetadataAttribute, AttributeUsage(AttributeTargets.Class)]
public class TargetDeviceAttribute : ExportAttribute, IDeviceSpecific
{
public TargetDeviceAttribute(string deviceId)
{
this.DeviceId = deviceId;
}
public string DeviceId { get; private set; }
}
I've found that what's happening is that the part RelaySystemClientRequestProcessor
corresponds with two exports: IClientRequestProcessor<RelaySystemModel>
, which is the export I'm interested in and the interface I try to import the part with, and RelaySystemClientRequestProcessor
. However, the "DeviceId" metadata is only associated with the latter and not the former, which isn't helpful.
There are several ways that I believe this could be resolved though I haven't fully tested:
Applying the attribute
ExportMetadata("DeviceId", "<<foo>>")
to all of my exported parts.Changing the
TargetDeviceAttribute
to use the constructorpublic TargetDeviceAttribute(string deviceId, Type exportType) : base(exportType)
.
I'm not in favour of these solutions; the former would be problematic in case I wanted to change the metadata key, and both would involve changing the way I export all my parts.
What I'm wondering is if MEF2 provides a way to export metadata like in MEF1: by creating a custom metadata attribute and having it apply that metadata to all exports associated with a part. Is this possible?