Exports and Metadata

Declaring Exports explained the basics of parts exporting services and values. In some cases it’s necessary to associate information with exports
for a variety of reasons. Commonly it’s used to explain about the capabilities of an specific implementation of a common contract. This is useful to allow imports to either constraint the export that can satisfy it, or to import all available implementations
at the time and check their capabilities in runtime before using the export.

Attaching Metadata to an Export

Consider the IMessageSender service introduced earlier. Suppose we have a few implementations, and they have differences that may be relevant to the consumer of the implementations. For our example the transport of the message and whether is secure are important
information for a consumer (importer).

Using ExportMetadataAttribute

All we have to do to attach this information is to use the [System.ComponentModel.Composition.ExportMetadataAttribute]:

Using a Custom Export Attribute

In order to do it more strongly typed than using the ExportMetadataAttribute, you need to create your own attribute and decorate it with
[System.ComponentModel.Composition.MetadataAttribute]. In this example we also derive from ExportAttribute, thus creating a custom Export attribute that also specifies metadata.

That’s all that is required on the export side. Under the hood, MEF is still populating a dictionary, but this fact becomes invisible to you.

Note: You can also create metadata attributes that are not themselves exports, by creating an attribute which is decorated with MetadataAttributeAttribute. In these cases the metadata will be added to Exports on the same member where the custom metadata
attribute was applied.

Importing Metadata

Importers can access the metadata attached to the exports.

Using Strongly-typed Metadata

To access metadata in a strongly-typed fashion created a metadata view by definining an interface with matching read only properties (names and types). For our sample it would be an interface like the following:

Using Weakly-typed metadata

To access metadata in a weakly-typed fashion, you import uisng the type System.Lazy<T, TMetadata> passing IDictionary<string,object> for the metadata. You can then access the metadata through the Metadata
property which will be a dictionary.

Note: In general we recommend the strongly-typed method for accessing metadata, however there are systems that need to access the metadata in a dynamic fashion, which this allows.

Metadata filtering and DefaultValueAttribute

When you specifiy a metadata view, an implicit filtering will occur to match only those exports which contain the metadata properties defined in the view. You can specify on the metadata view that a property is not required, by using the
System.ComponentModel.DefaultValueAttribute. Below you can see where we have specified a default value of false on IsSecure. This means if a part exports IMessageSender, but does not supply IsSecure metadata, then it will still
be matched.

I'd like to note that when looking up the Metadata key in the Export Metadata Dictionary that the Key is case sensitive. It would be nice if it wasn't case sensitive or gave an option to disable that but no where in the documentation did I find that the key lookups were case sensitive.

OK, so it took me a few hours, but I figured it out. In your attribute class, it has to call the base constructor passing in the type of your metadata attribute: base(typeof(IMessageSenderCapabilities))

Furthermore, you cannot access the Imported property inside of the importer class' constructor, it will throw a TargetInvocation exception.

In preview 5 I'm trying ExportCollection<MyDelegate> and my exports elsewhere are static functions that export MyDelegate. I get an "internal error" inside MEF, in ReflectionProperty.GetValue, Assumes.NotNull(this._getMethod); If I use IEnumerable<MyDelegate> it works fine, but then I can't get the metadata - at least, not the expected way. See http://mef.codeplex.com/Thread/View.aspx?ThreadId=56225 for workaround.

Can we get this updated - I just spent a while looking for ImportRequiredMetadata (which has obviously been removed). Replacing this with an example showing the best way to achieve the same would be good.