New MEF Drop (Preview 9) on CodePlex!

I was pretty excited to see that there’s a new drop of MEF up on CodePlex – if you’re a reader here then you’ll know that MEF will ship with Silverlight 4 and with .NET Framework 4.0 ( it’s already in the beta/RC bits in both cases ) and there are versions on CodePlex targeting Silverlight 3 and .NET Framework V3.5 Sp1.

The phrase that I like to use to describe MEF is that it is a;

framework for composing applications out of a set of loosely coupled parts that are discovered and can evolve at run time

that’s not an official “MEF team” definition – it’s just Mike’s view and there’s many places where MEF makes sense such as in building pluggable application architectures and also in implementing patterns like MVVM.

If you’re looking to get started with MEF then here’s some quick resources;

  1. Glenn Block’s new MSDN Magazine Overview Article and Glenn’s Blog
  2. The Overview on CodePlex
  3. The Programming Guide on CodePlex
  4. My Channel 9 Videos 
  5. My London Silverlight User Group Session Recording

but if you’re already up and running then what’s new in the CodePlex drop for the Silverlight developer? Three small changes and a larger addition;

  1. Updated samples!
  2. Renaming and changes to PartInitializer
  3. Renaming and moving of PartCreator
  4. Renaming and changes to CompositionHost.InitializeContainer
  5. A new DeploymentCatalog class. Mmmmmm 🙂

Let’s run through those in order;

Updated Samples

Firstly, it’s worth saying that there are updated samples to show this functionality so if you’re a “samples kind of person” then take a look at the updated HouseSpacePlanner sample and the new DeploymentCatalog ( more on that in a moment ) sample to get going.

Renaming of PartInitializer to CompositionInitializer ( and some new tricks )

MEF deals with imports and exports. We can have a piece of code like this one that exports some mythical functionality via an interface IPlugin;

  public interface IPlugin
  {
    void DoPluginFunctionality();
  }

  [Export(typeof(IPlugin))]
  public class PluginA : IPlugin
  {
    public void DoPluginFunctionality()
    {
    }
  }

and we then have a particular kind of IPlugin like PluginA in the code above which exports itself via MEF as an IPlugin. If we were building some kind of application shell class that made use of this pluggable functionality then we might write code such as;

  public class ApplicationShell
  {
    public ApplicationShell()
    {
      CompositionInitializer.SatisfyImports(this);
    }
    [Import]
    public IPlugin Plugin;
  }

and note that the ApplicationShell does two things. One is that it imports an IPlugin and the other is that to “tell MEF” that it wants that import ( and any recursive imports ) satisfied it calls CompositionInitializer.SatisfyImports in its own constructor on “itself”. This class has been renamed from PartInitializer and I think that the new name is much more indicative of what the method call is actually doing;

[NOTE] CompositionInitializer.SatisfyImports does a whole bunch of work around making sure that a “default” container is set up for the application and populated with AssemblyCatalogs for the assemblies found in the application’s deployment.

Now, the standard programming model in MEF is based around attriibutes like you see with [Import] above but this is just one possibility – “the attributed programming model”.

Different programming models are a bit of an advanced topic but I experimented with different programming models here and one of the things that I found was that the PartInitializer.SatisfyImports call had only one option which was tightly tied to the attributed programming model. That is – you passed it an object instance and it expected to find attributes on that object instance to drive its composition.

In the new drop, CompositionInitializer.SatisfyImports has a new overload so that it can take any ComposablePart rather than just an object instance. That means that you can now stick with using CompositionInitializer.SatisfyImports() even if you’re working with alternative programming models which is really cool.

Renaming of PartCreator to ExportFactory ( and a new home )

The previous code-snippet is fine but it means that one and only one instance of IPlugin is available to my ApplicationShell. Sometimes I might want MEF to not import an actual instance of an import but, instead, the means to create an instance. You can imagine some shell like Outlook that imports an email view and you might well want to have more than one instance of that email view showing different folders and so on and so the importing application needs to be able to create those views dynamically.

This is what ExportFactory is for. It was previously named PartCreator and if we changed our code to look something like;

  public class ApplicationShell
  {
    public ApplicationShell()
    {
      CompositionInitializer.SatisfyImports(this);
    }
    public IPlugin MakeNewPlugin()
    {
      return (this.Factory.CreateExport().Value);
    }
    [Import]
    public ExportFactory<IPlugin> Factory;
  }

then you can see that I’ve now done my import via ExportFactory<IPlugin> and so what MEF composes for me is a factory that knows how to make IPlugin instances whenever I like ( as used in the MakeNewPlugin() method above ).

The other thing to note about ExportFactory is that it has moved assemblies. Whereas PartCreator was in the System.ComponentModel.Composition.dll assembly, the new ExportFactory is in the System.ComponentModel.Composition.Initialization.dll.

The driving force behind that change is to ( for Silverlight 4 ) make System.ComponentModel.Composition.dll an assembly that you can reference from code libraries that can be shared to target both the .NET Framework on the desktop and the Silverlight .NET Framework. Very cool! For more on shared assemblies, see here.

Renaming of CompositionHost.InitializeContainer() to Initialize() and Changes

In the previous code snippets, I never went anywhere near CompositionHost because there would be no need to if I was happy with the default behaviour that CompositionInitializer.SatisfyImports for me drives ( see the previous text marked [NOTE] ).

However, if I want to change the default container that CompositionInitializer.SatisfyImports relies upon then I can set up that container via CompositionHost.Initialize() ( renamed from CompositionHost.InitializeContainer() ).

So, as long as I run code like this code below before any calls to CompositionInitializer.SatisfyImports() then I can get to alter the default container that will be used. As a simple example, I can use something like a TypeCatalog to introduce my types rather than rely on the default behaviour built around AssemblyCatalog ( note – there’s no real reason to do this, it’s just a cheap example here );

      CompositionHost.Initialize(
        new TypeCatalog(typeof(PluginA)));

      ApplicationShell shell = new ApplicationShell();

now, the very sharp-eyed amongst you might have noticed that Initialize() has a new overload here in that it now has an overload that takes any number of ComposablePartCatalog instances which means that you can avoid having to get involved with creating a CompositionContainer unless you have a specific need to and just simplifies things and reduces lines of code.

A New DeploymentCatalog Class

For me, this is a case of saving the best until last 🙂

The new drop has a class called DeploymentCatalog.

I demo’d a similar thing in my talk at the London Silverlight User Group and said that this may show up in Silverlight 4 by the time of release. There’s no promises around that but I hope that the class showing up here on CodePlex suggests that there’s still a good chance of it 🙂 In the current Silverlight 4 beta toolkit there are classes PackageCatalog and Package that perform a similar function but ( imho ) aren’t as good to work with.

MEF ( for Silverlight ) has a bunch of catalogs from which parts can be pulled – TypeCatalog, AssemblyCatalog, AggregateCatalog.

DeplomentCatalog is an additional ComposablePartCatalog which can be used to download a XAP from a URI and it will then “do the right thing” around exporting the composable parts found in that XAP.

I had an example in the talk that I gave in London which had components something like in the picture below – the idea being that I might be writing an application a little like iTunes/MediaPlayer and I want to have a pluggable component that knows how to get album information for a particular album. That component may well delegate part of its work like finding the actual album artwork to another pluggable component;

image

where my interfaces are really simple ones like this;

  public interface IAlbumInfoProvider
  {
    AlbumMetadata GetAlbumInfo(string title);
  }
  public interface IAlbumArtProvider
  {
    Uri GetAlbumArt(string title);
  }

and then I have some very hard-coded implementations;

[Export(typeof(IAlbumArtProvider))]
  public class AlbumArtProvider : IAlbumArtProvider
  {
    public Uri GetAlbumArt(string title)
    {
      Uri uri = null;

      if (title == "Blood On The Tracks")
      {
          uri = new Uri("/Images/BloodOnTheTracks.jpg", UriKind.Relative);
      }
      return (uri);
    }
  }

 [Export(typeof(IAlbumInfoProvider))]
  public class AlbumInfoProvider : IAlbumInfoProvider
  {
    [Import(AllowRecomposition=true)]
    public IAlbumArtProvider AlbumArtProvider { get; set; }

    public AlbumMetadata GetAlbumInfo(string title)
    {
      AlbumMetadata metadata = null;
      
      if (title == "Blood On The Tracks")
      {
        metadata = new AlbumMetadata()
        {
          Artist = "Bob Dylan",
          Title = title,
          ImageUri = this.AlbumArtProvider.GetAlbumArt(title)
        };
      }
      return (metadata);
    }
  }

I packaged these 2 implementations into 2 separate XAP files and dropped them onto my site-of-origin so in Visual Studio it looks like;

image

and then my main application shell does an import for an IAlbumInfoProvider as in;

    [Import(AllowRecomposition=true, AllowDefault=true)]
    public IAlbumInfoProvider AlbumInfoProvider { get; set; }

with that in place, I can use the DeploymentCatalog to download my additional XAPs asynchronously as the lifetime of the application progresses;

      AggregateCatalog aggregateCatalog = new AggregateCatalog();

      foreach (var item in new string[] { 
        "AlbumInfoProvider.xap",  // ( uri )
        "AlbumArtProvider.xap"    // ( uri )
      })
      {
        DeploymentCatalog deploymentCatalog = 
          new DeploymentCatalog(item);

        aggregateCatalog.Catalogs.Add(deploymentCatalog);

        deploymentCatalog.DownloadCompleted += (s, e) =>
          {
            // should check e.Error and e.Cancelled
          };

        deploymentCatalog.DownloadAsync();
      }
      CompositionHost.Initialize(aggregateCatalog);

This is very, very neat. What actually happens as this application runs is something like;

  1. The application runs up.
  2. Creates a DeploymentCatalog for my XAP file “AlbumInfoProvider.xap” and starts to download.
  3. Creates a DeploymentCatalog for my XAP file “AlbumArtProvider.xap” and starts to download
  4. Puts both DeploymentCatalogs into an AggregateCatalog and sets that via CompositionHost.Initialize() to be my “default” catalog.
  5. Then a call to CompositionInitializer.SatisfyImports will run from my MainPage which imports the IAlbumInfoProvider as in the snippet above.
  6. That call is likely to find no exports that match.
  7. As downloads complete, the exports will be found and MEF will recompose both;
    1. The import that my MainPage does for IAlbumInfoProvider
    2. The import that my AlbumInfoProvider does for IAlbumArtProvider

until all the functionality that was imported is download asynchronously over the network and recomposed by MEF into working componentry.

Neat. I wrote this slide;

image

and I think DeploymentCatalog is a great step towards making this easier.

 

Enjoy!