Metadata Inheritance in Managed Extensibility Framework (MEF) in .NET 4.5
I have been playing around with Managed Extensibility Framework (MEF) of .NET 4.5 for a while now. Overall, it is a great framework for designing many plug-in/extensibility scenarios of .NET applications, web, desktop or even Windows Store (Metro). One area that got interesting in my MEF experiment was the way in which metadata worked in the case of inherited exports. As you know, in general, there are three ways to attach metadata to export parts (classes decorated with Export or InheritedExport attribute):
- Via ExportMetadata attribute
- Define a class deriving from ExportAttribute type, define one or more read-only properties representing the metadata and mark that class with MetadataAttribute type
- Define a class deriving from Attribute type, define one or more read-only properties representing the metadata and mark that class with MetadataAttribute type
In my experiment, the first two options were like breeze. The third turned out be a bit challenging to get it correct; I was not sure if the behavior I noticed was the intended one or a bug. Here is what I did:
- Define a class deriving from Attribute type and mark it with MetadataAttribute. This class will have read-only properties each representing the required export metadata. In fact, the metadata properties were wrapped in an interface and the custom attribute class implemented that interface.
- Define my base export class marked with InheritedExport attribute and also the custom metadata attribute I created in step 1
Here is the code:
Then, I went on to apply this custom attribute to my base export part that also has InheritedExport attribute on it. I defined two more classed deriving from the base export and applied metadata with the custom attribute. At this point, there are three export parts, each with its own metadata tagged via the custom attribute - CustomMetadata. Here is the code:
I setup a simple composition container to test out the metadata:
However, the output of the above took me for a surprise and I spent hours trying to fix this but later I inferred from various blog posts, Stack Overflow responses and the MEF CodePlex site that this behavior is "by design" in MEF! I was expecting the respective mask and symbol metadata values of each export part to be printed; rather I got the mask and symbol of the base export part printed for all three.
As you can see, the metadata supplied at each inherited export type was completely ignored. Rather, the metadata specified at the base class was carried on to the inherited classes too (contradicting to what I read at http://mef.codeplex.com/discussions/82448/). One solution to this issue is to stay away from the InheritedExport and explicitly apply Export attribute on each export part specifying the base export type:
And the corresponding output is:
The other solution is to have the custom metadata attribute extend ExportAttribute (in addition to the metadata interface) as shown below:
Then apply this attribute on each export part (without explicit Export attribute, since the new custom attribute extends the ExportAttribute type):
The output remains the same: each export part correctly gets the metadata supplied via the new custom attribute.