import with "dynamic" metadata

Oct 26, 2009 at 2:37 PM

hello,

i got an app with multiple repositories and ive playing around with mef to get a neat ioc solution

basically i have a bit of ui that uses one of the available repos using some meta data. now my problem is this, in order to get this to work ive used an ImportMany attribute in the ui, but i'd rather use just a regular import because id like the ui to not have to worry about the multiple repos.

However, since there are multiple repos that doest work because the import is ambigous, so i need to have the metadata in in the import, but if i do that i cant change the metadata at runtime to switch repos[because the metadata is baked into the Import attribute], something that i need to do. i figure there is something with recompossition but im not sure how to put it together.. any pointers are welcome :)

Oct 26, 2009 at 9:42 PM

i guess what i really want to do is customize the behavior of the container when there is one import and multiple exports of the same contract. the default is to throw an exception, but i want to consult some other logic, settings in this case.

is subclassing CompositionContainer the way to go or is there a better way?

Developer
Oct 27, 2009 at 12:07 AM

Now you could try to force this behavior into the CompositionContainer or a custom ExportProvider but it really isn't scalable. How would you select this one out of many for each and every contract queried for?

One approach you could consider is something along the lines of Glenn's AdaptingCollection http://mef.codeplex.com/Thread/View.aspx?ThreadId=64387, in which case you would simply ImportMany into a custom collection and have the logic for selecting "the one" in that custom collection.

Oct 27, 2009 at 10:28 AM
Edited Oct 27, 2009 at 10:31 AM

my initial though was something similar to that thread, however it would have been interesting to have the importing part be unaware that there are actually more than one suitable export and also abstract out the configuration bit. i imagine an event that contains the import to satisfy as well as the appliccable exports available. in this perticular instance itsnot hard to decide what intance to use, its configured via settings where you basically select what repository to use,  that repository is then a singleton instance.

i guess another way of looking at it is that i'd like to define metadata for a single import [i.e not an ImportMany] and also be able to change that metadata at runtime..

 maybe this is something for mefContrib? :)

Oct 27, 2009 at 2:01 PM

what i mean is that i'd like to handle the conflict resolution centrally and not in each part. it doesnt seem like you recommend doing that in the CompositionContainer but is there any other extension points i can look at? conflict resolution between parts seems like a central part of something like mef right now it seems to me i have to make everything [ImportMany] to avoid the app to explode at runtime if some user puts a dll in the wrong place :)

Oct 27, 2009 at 2:36 PM

You could look into using a custom catalog for this. A very common pattern for this type of thing is to apply a decorator pattern where you have a decorating catalog which wraps an filters against an inner catalog based on some metadata. This works as long as the filtering is arbitrary and not tied to the particular part importing it. Meaning if there are two IFoos, I can choose in custom logic which one is returned, thus the importer can have a single import. The filtering logic would live in the Parts property implementation of the custom catatalog. If you look on our wiki page you can find a filtered catalog example that illustrates filtering by metadata.

More difficult would be to address filtering based on the importer. This would require quite a bit more work.

HTH

Glenn

Oct 27, 2009 at 4:04 PM
Edited Oct 27, 2009 at 4:07 PM

i see.. very interesting.

in my case, thats exactly what i want. i want the importer to only know about the existance of one repository. the importer is happy with any repository it gets and do not want to figure out witch one is the correct one to use, that is the logic that i would put in a wrapper catalog you describe.

i havent found the wiki page you're reffering to though, it doesnt seem to be in the Learn more about MEF, The MEF Programming Guide, or sample documentation, but maybe im missing something?

-edit-

found it under parts lifetime:

http://mef.codeplex.com/wikipage?title=Filtering%20Catalogs

i always had the feeling mef was cool but its only recently ive really begun to appriciate it. the learning curve has a big bump in the beginning, but once you're over that... :) im currently in the process of integrating mef into our main software suite

Oct 27, 2009 at 6:55 PM

Yes that's the link I was just going to send you :-) It's somewhat buried so we should probably put it in the TOC. :-)

Another option to explore the approach in this post: http://codebetter.com/blogs/glenn.block/archive/2009/05/14/customizing-container-behavior-part-2-of-n-defaults.aspx

In it you'll see how you can define a "default" catalog for returning a single export in the presence of many. All would need to do to use it, is create a TypeCatalog and then add to it dynamically the particular one you want returned for single import requests. It's signficantly less coding, but it may or may not meet your scenario.

Regards

Glenn

Developer
Oct 27, 2009 at 10:10 PM

FYI: I've updated the FilteredCatalog sample at http://mef.codeplex.com/wikipage?title=Filtering%20Catalogs to reflect the current previewed code.

Oct 28, 2009 at 9:27 AM
Edited Oct 28, 2009 at 9:41 AM

very interesting, thanks a lot :)

the problem you describe in you post glenn, is almost exactly the one i was facing. i went with the "LoggerService.DefaultLogger" approach but as you say, its not optimal.

your solution takes me closer but i think i need to make a custom ExportProvider because i also want to have the app recompose if the user changes the "active" export (if they select another logger in some config window for example). If i understand things correctly, i would then raise the ExportsChanged event in my custom export provider, in other words theapp would look something like this,

  • a custom export provider wrapps all the other [configurable] export providers
  • a bit of ui gets a reference to the custom exportprovider (perhaps the exportprovider itself is an export the ui imports)
  • a change in the ui get pushed into the custom export provider, the export provider raises the ExportsChanged, the app gets recomposed with the new "active logger" (for example). The imports of ILogger are not aware of any change, they just keep calling their ILogger instance, witch now happens to be something else.

do you think that would make sense?

@wes awsome, thanks :)  i'll check it out right now

Oct 28, 2009 at 9:58 AM
Edited Oct 28, 2009 at 1:02 PM

or is it the ComposablePartCatalog i should subclass? i dont think i understand the relation between ExportProviders and catalogs, they kinda seem to do similar things, but the compositionContainer taks only one catalog and multiple ExportProviders

-edit-

i see the catalog is turned into a ExportProvider with the CatalogExportProvider class, but then why are the not only ExportProviders? im sure there is a very good reason, i just dont understand it yet :)

when should i use the ExportProvider and when should i use ComposablePartCatalog, generally speaking?

Developer
Oct 28, 2009 at 5:07 PM

You are correct that catalogs end up getting wrapped in the CatalogExportProvider.

The way I like to think about catalogs vs ExportProviders is that you can think of catalogs as containing a set of types and ExportProviders as containing a set of activated instances of types. So in the CatalogExportProvider case it uses a catalog to find the appropriate types (or exports) and it manages activating them and caching them as needed. While this may be a simplification I think it illustrates the general differences.

Oct 30, 2009 at 10:10 PM

Thank you for all the info and tips  :) i'll do some more experiments and see where i end up

mef is really growing on me now that i understand it better :)

Nov 4, 2009 at 10:00 AM
Edited Nov 4, 2009 at 12:19 PM

 

Thank you Glenn for your blog entries on "Customizing container behavior" (http://codebetter.com/blogs/glenn.block/archive/2009/05/14/customizing-container-behavior-part-2-of-n-defaults.aspx)

In order to adapt the given source code of Glenn to the newest release of Mef, the params of method GetExportsCore of any ExportProvider must be changed as the following code

 

protected override IEnumerable<Export> GetExportsCore(ImportDefinition importDefinition, AtomicComposition atomicComposition)

@Glenn: could you please explain a little bit the usage of AtomicComposition. Thanks!

Steven