MEF in .NET for Metro style apps RC

Jun 1, 2012 at 5:43 PM

Hi there - yesterday we announced some changes to MEF in the RC for Metro style apps:

http://blogs.msdn.com/b/bclteam/archive/2012/05/30/mef-and-tpl-dataflow-nuget-packages-for-net-framework-4-5-rc.aspx

We've had a couple of people ask us about using Cocoon with the new version. We expect that migrating forwards should be fairly simple, but just wanted to let you know that we are here to help on the MEF discussion forum (http://mef.codeplex.org) or on this thread if you have any questions.

We've also done some work around the MEF lifetime model in this version - [Shared] and [SharingBoundary] attributes simplify 'per-viewmodel' sharing scenarios a lot - and would be interested in your experiences with this if you decide to support this in Cocoon.

All the best with the project!

Nick (from the MEF team)

Coordinator
Jun 3, 2012 at 10:34 AM

Hi Nick,

Thanks for the message. It's nice to hear that people have been showing interest in the Cocoon framework.

I've got the RC installed on my development PC now so the first job I've got lined up is to get Cocoon working with the new bits. I've had a brief look at the changes and I don't see any major hurdles. It is good to hear that you have moved MEF for Metro over to the lightweight composition engine - all my performance tests had been fine but always in the back of my head I had some concerns regarding MEF composition affecting startup time for Cocoon based apps. The [SharingBoundary] attribute does sound useful too - will need to see how this integrates with Cocoon.

Cheers,

    Andy

Jun 3, 2012 at 8:37 PM
Edited Jun 3, 2012 at 8:39 PM

Hi Andy

I tried to changing the references to System.Composition from System.ComponentModel.Composition (MEF 2 Pre-release) like suggested by the .NET 4.5 Change Log Document. The issues I have right now are with the Catalogs. Because the newer MEF doesn't support the catalogs, I am encountering a lot of issues especially the navigation and bootstraper parts of the framework. Are there any updates in your pipeline right now? I am using this framework for one of my projects right now. Any light in this area is really helpful.

Coordinator
Jun 4, 2012 at 9:28 AM

Hi,

As you have found there are a number of changes that are required when porting to the new version of MEF for Metro-style apps. I am in the process of updating Cocoon to support the Release Preview - both the new vesion of MEF and a number of other changes in this release. My aim is to get this pushed out to CodePlex in the next few days.

Will report back soon!

    Andy

Jun 4, 2012 at 7:10 PM

Hi Andy

Thank you very much.

--Ram--

Jun 5, 2012 at 11:11 PM

Hi Andy,

Glad it looks like a smooth process. Regarding the lifetime/sharing features, there are two ways we have improved MEF that may benefit Cocoon:

  1. Easier to avoid reference leaks
  2. Easier to scope "part instances" to a single view-viewmodel pair

MEF traditionally provides two facilities that can be the source of reference leaks - recomposition and lifetime management. In MEF for Metro style apps we've eliminated recomposition, as the scenarios in which it applies are not typically present in Metro applications. Lifetime management is the other source of issues: repeatedly calling GetExport() or SatisfyImports() can cause non-shared parts to be created, and these need to be released explicitly (via MEF) 
before the GC will reclaim them.

In MEF for Metro style apps there is a simple recipe for ensuring that disposable parts are not tracked beyond their required lifetime: so long as exports are created through an ExportFactory<T>, they will be reclaimed by the GC when no longer required, regardless of whether or not they implement IDisposable.

For a framework like Coccoon this impacts how views and viewmodels are created. Code like:

var view = container.GetExport(viewType);

var viewModel = container.GetExport(viewModelType);

can be replaced with code that uses an ExportFactory. There is one twist here, because Cocoon will use service location so the types ExportFactory<MyView> etc. aren't known at compile time. Instead, an export factory can be used to create a composition context. Assuming we import this as:

[Import]

public ExportFactory<CompositionContext> CompositionContextFactory { get; set; }

Then creating a view-viewmodel pair looks like:

var context = CompositionContextFactory.CreateExport();

var view = context.Value.GetExport(viewType);

var viewModel = context.Value.GetExport(viewModelType);

The context object can be allowed to go out-of-scope, or else, to support IDisposable views or viewmodels, it can be stored and then disposed when the view-viewmodel pair are no longer required.

By retrieving the view and viewmodel from the same composition context, it is possible for them to share dependencies on a per-view-viewmodel basis. Let's call this the "vvm" sharing boundary. If there's a part that is specific to a single view-viewmodel pair it can be marked as such with [Shared]:

[Shared("vvm"), Export]

public class EventSubscription { ... }

To mark the composition context we're creating as the "vvm" sharing boundary, we can modify the import above:

[Import, SharingBoundary("vvm")]

public ExportFactory<CompositionContext> CompositionContextFactory { get; set; }

Now, any view and/or viewmodel that imports the EventSubscription part will get an instance that is unique to the view-viewmodel pair.

Hope this clarifies what I meant by my earlier remark about the improvements we've made. It would be great to hear your insights and again please let us know if you have any questions.

The startup performance difference should be negligible I think; some improvements have been made but we do also trade a little startup perf for better runtime perf. (If performance comes onto the radar let us know as it can be very scenario-specific.)

Regards,

Nick

Coordinator
Jun 6, 2012 at 10:03 AM

Hi Nick,

Thanks for the further information. I've managed to migrate Cocoon to the RP with the new MEF implementation fairly easily - I have a couple of MEF-unreleated stability issues I'd like to iron out before I publish publically though.

My main stubling block with porting the code was in the ViewFactory where I import "[ImportMany("CocoonPage")]IEnumerable<ExportFactory<object, IPageMetadata>> pageFactories" (as an aside, for the RP I changed the metadata from an interface to a class). Since I don't know the type of the page at compile time this is specified as "object". In the CP this picked up classes with an [Export("CocoonPage")] attribute even though these could be of an arbitary type. In the new implementation I have to specify both contract name and type - i.e. [Export("CocoonPage", typeof(object)].

Regarding exporting of views and viewmodels - I've been using a separate ExportFactory for each of these up to now. Being able to use an ExportFactory<CompositionContext> definately sounds the way to go in the future to enable a SharingBoundary to span across both elements of the view-viewmodel pair.

Andy

Jun 6, 2012 at 3:06 PM

Hi Andy - thanks for the heads-up, glad to hear it is going well.

Nick

Coordinator
Jun 14, 2012 at 9:27 AM

Since this thread seems to be capturing the ongoing progress with MEF integration in Cocoon I have some further information on the latest code drop,

The MEF dependencies have now been refactored into a separate assembly (Cocoon.MEF) with the bulk of the framework in the core assembly (Cocoon). For most users who are using the default MEF bootstrapper you will need to add both assemblies to your project. This change should pave the way to allow users to choose their composition container of choice (e.g. MEF, Autofac, Unity, etc.) and continue to use the Cocoon framework.

And as a sneak peak, convention based export of views and view models is in the pipeline...

Andy