Managed Extensibility Framework Preview 4, a grab bag of goodies.

If you haven’t seen Krys and David’s announcement,  we just released another drop of MEF (I need to hold myself from breaking out in hysterics when I say that ) on CodePlex.

This release contains a whole grab bag of goodies, some of which may initially taste like sour candies (breaking changes), but are sweet in the middle. Most importantly, we’ve done a significant set of enhancements to the MEF codebase around Lifetime, Diagnostics, and Debugging.

Summary of the breaking changes:

  • AllowNonPublicCompositionAttribute was removed. It is no longer needed MEF will always look at publics and non-publics.
  • ComposablePartCatalog was moved from System.ComponentModel.Composition to System.ComponentModel.Compositioni.Primitives.
  • AttributedTypesPartCatalog was renamed to TypeCatalog
  • AttributedAssemblyPartCatalog was renamed to AssemblyCatalog
  • DirectoryPartCatalog was renamed to DirectoryCatalog
  • AggregatingComposablePartCatalog was renamed to AggregateCatalog
  • Catalog Caching extensibility API’s have been made internal.
  • Mutability APIs on the container have been changed to accept a batch. AddPart and RemovePart methods were removed from the container, and you know must pass a CompositionBatch. The advantage of the batch is that you can now replace a single part in the container with a new part in a single operation. You can also add or remove multiple parts in a single operation. This comes in very handy when you have parts that are recomposing.

New features:

New wiki pages

We’ve (well really Hammett) fleshed out all the TBD topics, plus added a ton of new ones both in our programming guide and the arch section.

Diagnostics and debugging

Since joining the team once thing that I’ve heard over and over is just how bad our debugging experience was. Not only did i hear it…I experience it first hand, some times live on stage :-) Well fortunately Nick and his feature crew (David and Jad/Zhen) spent the last several months focused on righting this wrong.

We’ve made significant improvements in the debugging experience to address some problematic scenarios and deliver a foundation for diagnostics in all MEF features and extensions.

The differences to note are:

  • Multiple composition errors are structured in numbered groups each relating to a single root cause
  • The ‘causal chain’ (Resulting in: …) traces an issue all the way back to the root action that the application was trying to perform
  • The ‘origin path’ (Element: …) describes how each object involved in the scenario came to be in the composition in the first place
  • All of this information can be retrieved programmatically from the exception types if necessary

Another difference will be the visualization of exceptions when they occur.

Previously you would see something like the following, which was difficult to navigate.

clip_image002

With the changes, you will now see.

clip_image004

Lifetime Management and Creation Policy

Another concern we heard from customers was around how MEF handles lifetime management for parts. In previous releases we allowed the exporter to declare that a part has either a singleton or factory (transient) lifetime.

  • If a transient part implemented IDisposable, it’s resources would be released only when the container was disposed. Singletons would also be disposed in a similar manner. This forces transient parts which could container scarce resources to stay alive. For example if a part contains an unmanaged resource such as a database connection, it will stay open and not get recycled.  This is particularly problematic in server environments such as ASP.NET, where you have a limited number of resources shared by many active sessions. Not having the connections recycled could lead to starvation.
  • Another challenge of the previous approach was that the Part had to determine its lifetime policy. As parts are reusable across different apps, it is very likely that a part in one app is a singleton, while in another it needs to be transient. In the same app there are even cases where the same part needs to be transient in one case and singleton in another. In our previous bits, there was no way to address this.

Hammett and team (Wes, Daniel) have been working tirelessly to come up with a solution to this one. Hammett personally was no stranger to this problem form all the work he’s done on the castle stack. Upon joining the team this is one area that he was relentless about finding a solution to. I am thankful for his passion to see this through as there were several times we hit road blocks that seemed insurmountable.

In the new bits we have provided solutions to both of these problems.

  • We’ve renamed Singleton and Factory creation policy to Shared / NonShared.
  • Parts and Imports can now both declare creation policy. We’ve also added a new policy called Any, which allows a Part or an Import declare that it can work with either policy, i.e. a Part could have a policy of Any, where one  importer of the part’s exports has a policy of NonShared, while another importer has a policy of Shared. The grid below indicates the behavior in different scenarios.

 

Part.Any

Part.Shared

Part.NonShared

Import.Any

Shared

Shared

Non Shared

Import.Shared

Shared

Shared

No match

Import.NonShared

Non Shared

No match

Non Shared

An importer specifies the required policy through the use of the new RequiredCreationPolicy as can be seen below.

 [Export]
 public class Window : System.Windows.Forms.Form
 {
     [Import(RequiredCreationPolicy = CreationPolicy.NonShared)]
     public ExportCollection<IShape> Shapes { get; set; }
     ...
 }
  
  • Parts can now be explicitly released from the container by using the Container.ReleaseExport method. This method takes the export and traverses all its references that are non-shared and disposes of them if they implement IDisposable. This prevents what we call viral disposability where every part in the chain must implement IDisposable in order for the deepest child to be disposed. This is an extremely difficult problem for you to manage, and without this feature the likelihood of memory leaks is high.

For example, below you can see where the jobExport is explicitly released from the container.

 var container = new CompositionContainer(...);
 var jobExports = container.GetExports<IJob>();
 foreach(var jobExport in jobExports)
 {
      var jobProcessor = jobExport.GetExportedObject();
      jobProcess.Process();
      container.ReleaseExport(jobExport);
 }
  
  • A Non-shared part that has a recomposable import will be held conditionally based on the lifetime of its exports. If  the exports are gc’d the part will be released as well.

Be sure to check out the new wiki page on Lifetime for a much more detailed explanation.

This should be the last release where we introduce major API changes. We’re getting into the home stretch now, with Beta 1 around the corner. There’s still time for us to make fixes though so please get your feedback in.

Special thanks to Hammett for making sure this release got out the door and for the wiki page work. Also thanks to David and Daniel for their supporting efforts on the site. And thanks to the whole team for the awesome work they are doing! Lastly thank to you for your feedback!