MEF and XAML integration – Self composition

As I am hoping you heard from Nick, we just shipped MEF Preview 6 which includes a version of MEF for Silverlight 3! At the same time that we’ve been wrapping up on our .NET 4.0 release, we are busy working on a proper release for Silverlight vNext. The things you see in MEF Preview 6 for SL3 are just the beginning.

For SL, we are working on among other things, a set of MEF/XAML integration features. One of the problems we want to address is have parts within XAML which are (optimally automatically) composed. That is elements which normally would have to be manually added to the container in the code-behind in order for their imports to be satisfied. For example you drop a control anywhere in XAML that has imports, and it will get composed, regardless of where it sits within the XAML hierarchy.

In order to do this, we’re exploring a pattern we’re calling “Self composition”, that is an unreachable part (one that the container has no access to) can register itself to get composed. The way this works is the part (UIElement) calls a RegisterForComposition method on it’s load event. Calling the method, forces it to get composed by a host-specific strategy, one which in the case of SL might use an app-wide container, or one that is scoped. The important thing is the grid itself is not coupled to how it is going to get composed. For example, see the sample control below.

image

CustomGrid is a UserControl and it imports a set of IGridBehavior contracts. It’s using MEF for extensibility, thus the application author can deploy behaviors in the container’s catalog, which the grid will use.

So why does the grid need to register itself? Can’t it somehow be created from the container, which will then satisfy it’s imports? Short answer, no. First notice it has no Export, so it will not get picked up by a catalog. But second, the grid itself is declared within XAML, much like any other control, thus the XAML parser is the one who creates it. This would be the case whether it was manually defined within the .XAML file or if the control had been dragged from the toolbox. Thus our only option at that point is to grab the existing instance, and see that it’s imports get satisfied.

But, can’t we somehow take over the creation of the element from XAML, can we have the parser pass of creation to MEF? Actually the XAML 2.0 parser does provide hooks for factories for doing this, however after investigating, there’s a bunch of “devil is in the details” type issues around us doing this, which prevent us from taking this approach, including significant performance hurdles.

One option is to consider using markup extensions, for example an {ImportMany} ME that is a service locator that can be used within XAML. This would allow setting a Behaviors Dependency Property to all imports of IGridBehavior. This could work, however it means that every user of the grid, must explicitly specify one or more markup  extensions each time they use the grid, something that is leaky, and very poor from a usability perspective. As a side note, we are actually looking to add Markup Extensions for explicitly specifying imports on Dependency Properties, but that is geared more towards the user of the control vs the author.

Another option is to consider using attached properties, for example a “Compose” attached property would allow specifying Compose=True on our Grid.

image

Although this is less painful then having to specify all the gory details, it still means that the user of the control must explicitly set this wherever the use it. It means the control author cannot transparently decide to start using MEF without impacting every single XAML file that has ever sited that control.

Now all that being said, in general we're of mixed feelings on the team on the self-registration approach:

On the down-side:

  • Having parts have to compose themselves is a violation of SOC, in an ideal world, a part should never be responsible for telling itself to get compose. It’s generally a bad idea.
  • It’s a DRY Violation, my part has imports, yet I still have to “Tell” it to compose itself.
  • It poses several challenges relating to lifetime management.

On the up-side:

  • It allows for components which are instantiated by the runtime (in this case FrameworkElements in XAML), and normally unreachable by the container to be able to leverage MEF. This means frameworks (including our own) and applications can gradually migrate to leverage MEF rather than having to be completely re-written / designed in order to leverage composition.  It also means that you can use MEF where you see fit, regardless of whether the framework infrastructure supports it.
  • The pattern can even be extended outside of XAML, for example the same approach could work in Winforms, or ASP.NET Web Forms, or even Mobile. This is possible, because the design relies on a host-specific strategy, thus ASP.NET could provide a per-request container, etc.
  • Self-registered parts are not coupled to a specific container instance. It's up to the host strategy to decide the container.

What do you think? Do the pros outweigh the cons? Or should we hold off on introducing such functionality because it will cause more harm than good?

Your candid feedback is appreciated.