WP8 Breaks Bad (cooking with MEF)

By | March 19, 2014

Microsoft’s Managed Extensibility Framework is somewhat of an unsung hero in the .Net world in my opinion. The framework itself is insanely powerful and magical but when you combine it with other patterns and frameworks like MVVM it becomes pure sorcery. If you haven’t checked out MEFedMVVM, I suggest doing so after you get up to speed on MEF and what it is and offers you as a developer.

Recently, the DotNet team announced an update to their Microsoft.Composition nuGet package (MEF 2) which brings MEF-ability to Windows Phone 8.

To understand what MEF proper (ie: full-blown on the desktop) is and how you can use it, there are numerous examples throughout the interwebs. Check out this one and this one for a good start/overview.

What I couldn’t find, however, were actual code examples of using it on Windows Store or Windows Phone apps. The Windows Store support has existed for a few months now, so that surprised me. Let there be light!

Create a new Windows Phone 8 project

Easy enough. If you haven’t done this yet, um, hit the Bings.

Add the Microsoft.Composition nuget project

Keep in mind this is a pre-release nuget package, so you have to include the pre-release nuget channel to pick it up.

image

image

Now since you read the MEF articles I linked earlier you know that what we need are some “Exports” so that MEF can discover things it’s to inject later while running. For the purposes of this demo, we’re going to export many things that all say they belong to the same contract. We’ll then import them all and display them on the phone screen.

Create the common interface

Here’s some code. Add it to your project.

namespace PhoneApp1
{
interface INamedThing
{
string Name { get; }
}
}

Create the Exported types

Here’s some more code. Add it.

using System.Composition;

namespace PhoneApp1
{
[Export(typeof(INamedThing))]
public class NamedThingOne : INamedThing
{
#region INamedThing Members

public string Name
{
get { return "Thing One"; }
}

#endregion
}
}

Now here you see the important part. We have inherited from our interface, and exported this new type as an export of our interface type. This comes in to play later. The ‘Export’ tag makes this type discoverable by the MEF composer which in turn makes it eligible for injection.

Create the ViewModel

Here’s some code.

using System.Collections.Generic;
namespace PhoneApp1
{
class ViewModel
{
public IEnumerable<INamedThing> Things { get; set; }
}
}

We won’t do much with this just yet but you can already guess we’re going to make this the VM for our MainPage.xaml View and wire it up in the ctor as the DataContext as you’d expect. Then a ListBox in our View is going to iterate over the ‘Things’ and print out their Names via DataBinding.

But first let’s understand MEF’s role here.

In (mobile) MEF there are 3 key parts (in my opinion): Exports, Imports, and the Composer. Desktop MEF adds catalogs in to the mix, but those don’t concern us right now. The Composer is the dude that finds all your injectable objects and reacts to all the commands to join things up. In other words, you have to create a composer and tell him “look here for all your exports” then tell him “ok satisfy any imports now” then you get to use your things. Without doing those pieces, you end up with nothing. The ‘Export’ and ‘Import’ attributes end up meaning nothing.

Add the MEF composer

Where should we create our composer? For me, since the composer will discover all things (not just some things) I choose to put it in my App.cs file:

public partial class App : Application
{
...
private static CompositionHost _compositionHost;
/// <summary>Gets the MEF composition host for the application</summary>
internal static CompositionHost CompositionHost
{
get
{
return _compositionHost ?? (_compositionHost = new ContainerConfiguration()
.WithAssembly(System.Reflection.Assembly.GetExecutingAssembly())
.CreateContainer());
}
}

...

Let’s dissect this line of code. The CompositionHost is the dude that’s going to field the requests to discover and inject. We create him by first creating a container of assemblies that MEF should “spider” to find Export-tagged things. In our case we have only the one assembly, so that’s that. There are many different ways to compose your container, but this is by far the simplest in my opinion. Lastly, create the container from the configuration – this ends up being a CompositionHost object. I wrap this in a singleton-esque getter so it’s only ever composed once.

Retrieve the Exported objects

Now you’ve got a container that has spidered your assembly for all things marked with ‘Export’. The next thing to do is retrieve them and put them where your app can access these things. Enter the ‘Import’ and ‘ImportMany’ tags. They do exactly as you’d expect with the distinguishing characteristic of one-and-only-one (‘Import’) or one-or-more (‘ImportMany’).
For the purposes of our app, since we are going to Export many INamedThing objects and Import them in to an IEnumerable, we’ll be using ‘ImportMany’. Head back to your ViewModel and augment the Things property as follows:

[ImportMany]
public IEnumerable<INamedThing> Things { get; set; }

There is a subtle but important change from previous MEF structure here. The type of the import is inferred from the signature of the code to which it’s being applied. There is an overload for ImportMany(Type) but do not use it. To be honest I don’t know when if/you should.

You might thing you’re done here, but you’d be wrong. You haven’t told your composer that it needs to go through and wire things up. This is done on a per object basis. To do this to our ViewModel, we have to add a bit more code:

internal void Init()
{
App.CompositionHost.SatisfyImports(this);
}

Sadly since SatisfyImports requires an instance of an object you can’t do this in the constructor. There are a myriad of ways to make it happen, choose whichever you desire.

Wire up the View Model

Now it’s time to wire up ViewModel as the DataContext to our View. In MainPage.xaml add the following:

var vm = new ViewModel();
vm.Init();
this.DataContext = vm;

Notice we call the ‘Init’ method here to trigger the composer to satisfy its imports.

Now let’s add a ListBox with Items bound to our ViewModel’s “Things” property. Crack open the XAML and add:

<!--ContentPanel - place additional content here-->
<Grid x:Name="ContentPanel"
Grid.Row="1"
Margin="12,0,12,0">
<ListBox ItemsSource="{Binding Things}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>

And run!

image

Notice ‘Thing One’ showing up there? Now here comes the real beauty and where MEF is great for low-coupling and high-cohesion projects. What if you want to add a few more things to the list?

You have to do nothing more than simply create their classes and export them. The rest you get for free. Simply adding:

[Export(typeof(INamedThing))]
public class NamedThingTwo : INamedThing
{
public string Name { get { return "Two"; } }
}

[Export(typeof(INamedThing))]
public class NamedThing3 : INamedThing
{
public string Name { get { return "3"; } }
}

[Export(typeof(INamedThing))]
public class Named4Thing : INamedThing
{
public string Name { get { return "Four (4)"; } }
}

Greets you with:

image

Upon merely a build & re-deploy.

Now imagine that you separate out your classes to other assemblies, or simply add new classes to one folder w/in your project. The ease with which you can now add and remove features and objects to your applications becomes MUCH greater, and your confidence in your changes goes up dramatically – you know that you *only* added a feature, you didn’t muck with the view, change the view model, write a bunch more code, just added a new class.

Go forth and cook your apps with MEF!