Hannish
Hannish

Reputation: 1532

MEF update exported part metadata (the metadata view is invalid because property has a property set method)

I have an application and I'm using MEF to compose it. I want to know if it is possible to update the Metadata information of the parts after they were imported.

The reason to do this is the following: I display the imported parts' name and an typeof(int) property in a ListBox, and they are not loaded until the corresponding ListBoxItem is selected (pretty standard). Now I want to update the Metadata info of one part when some event raises, so the displayed info in the ListBox is somethind like "[Part name] ([new number])".

I'm importing the metadata as an Interface that defines it's info, but when I set the int property to be editable (with a set accesor) I receive the following execption at composition time:

"The  MetadataView 'myMetadataInterface' is invalid 
 because property 'myInt' has a property set method."

Is there ANY way to achieve this? Or is the metadata ALWAYS read only once the part is created?

I know this question looks weird, but it doesn't make it any less difficult and therefore interesting ;-)


EDIT (based on Lee's answer, in order to keep people to the core of the question)

I just want to know if it is possible to update a Metadata property after the part is composed, but before it is actually loaded (HasValue == false). Don't worry about filtering or finding the part.

I added a property to the export inteface, which is meant only to be represented in the UI and to be updated, this property has no other function and the parts are not filtered by it.

Thanks

Upvotes: 2

Views: 901

Answers (1)

Lee Louviere
Lee Louviere

Reputation: 5262

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.

citation

Short Version (EDITED in after question edit).

You shouldn't ever need to update metadata at runtime. If you have some data that should be updated and belongs to a mef part, you need to choose to either have it be updated by recompiling, or store that data in a flexible storage outside of the dll. There's no way to store the change you made in the dll without recompiling, so this is a flawed design.

Previous post.

Altering values on the view would by lying about the components loaded. Sure the metadata is just an interface to an object that returns initialized values; sure you can technically update those values, but that's not the purpose of metadata.

You wouldn't be changing the Name field of an instance of Type. Why not? Because it's metadata. Updating metadata at runtime would imply that the nature of the instance of real data is somehow modified.

This line of code, if possible, wouldn't introduce the Triple type.

typeof(Double).Name = "Triple";
var IGotATriple = new Triple();

If you want to alter values, you need to just make another object with that information and bind to that. Metadata is compiled in. If you change it after a part is loaded, it doesn't change anything in the part's source, so you'd be lying. (unless you're going to have access to the source-code and you change it there and recompile).

Let's look at an example:

[Export(typeof(IPart))]
[ExportMetadata("Part Name","Gearbox")]
[ExportMetadata("Part Number","123")]
[PartCreationPolicy(CreationPolicy.NonShared)]
public class GearBoxPart : Part { public double GearRatio ... }

Now, let's assume that you had a UI that showed available parts and their numbers. Now, the manufacturer changes the part number for whatever reason and you want to update it. If this is possible, you might want to consider storing part number in a manifest or database instead. Alternatively you'd have to recompile every time a part number changes.

Recompile is possible. You have a controller UI that does the above, but instead of updating the metadata, you submit a request to rebuild the part's codefile. The request would be handled by parsing the codefile, replacing the part number, then sending off for a batch recompile and redistribute the new dll. That's a lot of work for nothing IMO.

So, you setup a database. Then you change the object metadata to this.

[ExportMetadata("OurCompanyNamePartNumber","123")]

Then you have a database/manifest/xml that maps your unique permanent static part number that your company devises to the current part number. Modifications in your control UI update the database/manifest/xml.

<PartMap>
    <PartMapEntry OurCompanyNamePartNumber="123" ManufacturerPartNumber="456"/>
    ...
</PartMap>

Then the end-user UI does lookups for the part by manufacturer part number, and the mef code looks in the PartMap to get the mef part number.

Upvotes: 3

Related Questions