Controlling import resolution by a pluggable strategy

Jan 26, 2010 at 1:54 AM

Hi,

we've been evaluating MEF for the purpose of using it for our enterprise application, so please pardon me for an ignorant question.

I've been looking through the guide and API and the feeling that I got so far was that most of the resolution logic for imports lies withing the framework, and the typical way of affecting it is using metadata attributes.

For example, if I want to import an interface I1, and there are two class exporting it, C1 and C2, then the ways for me to pick one of them is either by:

a) metadata requirements

b) using collection import and then iterating over a collection and figuring out which import is the best myself.

What I needed was a little bit more control over import without the need to write complicated code at the import side. I wanted to extract this resolution logic in a strategy which I can then reuse.

Consider an example; I have a generic data-view framework. The view containers describe view placeholders within them using some sort of categorization (for example, "a tree view", "a thumbnail list", "a one-line list", "an interactive workspace"). These categories specify what kind of view is expected at the placeholder - "a tree view" would want a view which is a one line with an icon, while "a thumbnail list" would expect something with an image and label, roughly.

The views are exported by modules together with data. The view has attributes defining its properties, but it also exports some dynamic information, such as image size or whether it is readonly. Among others, there may be specifiers about what kind placeholder this view is most suitable for - "a one-line list" or "a tree view" or "an interactive workspace".

When the data need to be displayed by a container, it tries to find a view for it. It looks for a view matching the placeholder criteria. Imagine, this lookup is performed in many places, but the logic is generic among all places. By defining this categorization, and annotating both placeholders and views, it removes a need for containers to know anything about views it will display, and views to know anything about containers they will appear in.

Two things you may see from the way I'm doing this view discovery:

a) the criteria is dynamic. It is not limited by the compile time attributes, but may be controlled by dynamic properties

b) there is a separable and reusable part of logic responsible for matching of imports with exports

These two requirements lead me to the need of a strategy-based resolution. I heard that currently ImportDefinition is probably the place where the hard-coded strategy resides, but I was wondering if there are ways to insert pluggable strategies for different circumstances.

Thanks.

Denis

Developer
Jan 26, 2010 at 5:44 PM

Most of your assessment is correct we generally don't have a way to select imports in a dynamic fashion. You are correct that the ImportDefinition is where the actually selection logic lives but it would be very difficult and not suggested that you add custom dynamic logic into them. First ImportDefinitions need to be static and fixed for the lifetime of the import/part/catalog because the composition isn't designed to handle changing selection logic. Second it isn't as simple as writing a custom ImportDefinition because you would need to write pretty much a complete custom programming model which is non-trivial. 

Another option you didn't consider but will allow you to write reusable code is a variation of your option b) above, which is to use a custom collection. Have a look at the AdaptingCollection sample at http://codepaste.net/ktdgoh. Also it might be worth reading http://blogs.msdn.com/dsplaisted/archive/2009/08/10/import-cardinality-and-picking-which-export-to-use.aspx which talks about your options in this area.

Jan 26, 2010 at 6:01 PM
Edited Jan 26, 2010 at 6:05 PM

Hi Denis

I understand what you are trying to do. There are several ways to address the particular problem you are describing, but each of them will require some work. In general it sounds like you need to change MEF's resolution policy do something that dynamically applies your own policy. There are various ways to do this depending on the need.

1. Using filtered catalogs. With a filtered catalog you can filter against a set of part definitions with your own logic, for example based on some state values. See our wiki page on Filtered catalogs here: http://mef.codeplex.com/wikipage?title=Filtering%20Catalogs&referringTitle=Guide

2. Using hiearchical containers: You can create child containers which have a scoped set of dependencies that are specific the the particular graph you are building up. You can add specific instances / exports directly to the child container which will only be visible to the children. You can also combine this with filtered catalogs for more control. You can find out more about child containers in this thread: http://mef.codeplex.com/Thread/View.aspx?ThreadId=46796 also

3. Creating a custom ExportProvider. With ExportProviders you can control the resolution within MEF and apply your own policy. There's some interesting posts out in the wild on ExportProviders, like this one: http://www.wintellect.com/CS/blogs/jlikness/archive/2009/12/02/silverlight-mef-custom-exportprovider-for-attached-xaml-exports.aspx. You can create a custom decorator Export provider that wraps another export provider and filters the exports coming out based on custom policy.

Thanks

Glenn

Jan 27, 2010 at 8:05 AM

Hi guys,

thanks for your quick replies. I like the option (a) proposed by Daniel Plaisted - PolicyBased<T> seems like a good compromise (and it is probably similar to what you mean by "adapting collection"?). It will encapsulate the strategy, which can be defined elsewhere.

Thanks.

Denis