In April, I was in the UK for speaking at the VBUG conference and I was impressed by a demo given by Josh Twist. He built using MEF and WPF a “marketplace” application. The goal of the application was mainly showing the dynamic capabilities of adding new functionality to an application through MEF (or in full, the Managed Extensibility Framework for Silverlight 4).
For a presentation I’m giving shortly, I rebuilt something similar but in Silverlight: the MEF Marketplace in Silverlight. The setup is the following: a user gets an overview of apps he purchased in the market place and can run these on demand. The market place app will download the applications available to the user after the application has started, so this app mainly is a hosting shell for the other ‘purchased” applications to run in. Of course, the sample is a demo and can be extended quite a lot. For example, in the current implementation, I hard-coded the list of purchased apps and there’s no option to buy new ones. Also, it could be extended so that when new apps are purchased, a duplex service notifies the client of this and MEF downloads the new app in the background.
But, instead of talking of what could be added, let’s take a look at what I currently built already! Here’s a screenshot of the application showing the "purchased” applications.

And here’s one of the apps (the Flickr Image search) running inside the "market place shell”.

Time for some code. Let’s begin with the market place itself.
I defined a contract interface for all applications that can be loaded in the market place, IMarketPlaceApplication.
public interface IMarketPlaceApplication
{ string ApplicationName { get; } FrameworkElement MarketPlaceIcon { get; } FrameworkElement MainView { get; }}
This interface defines that all my apps will (of course) have a name, a default view which will load as the landing screen when the app is loaded (MainView.xaml) and an icon to show in the list (MarketPlaceIcon.xaml). As these 2 latest ones are XAML files, you can put in whatever you like.
A very easy application that will be possible to load from MEF is the HelloWorldApplication. The project structure of this app is as follows:
As you can see, there’s a class called HelloWorldApplication, which implements the IMarketPlaceApplication and 2 xaml files. The HelloWorldApplication code is shown below:
[Export(typeof(IMarketPlaceApplication))]
public class HelloWorldApplication: IMarketPlaceApplication
{
#region IMarketPlaceApplication Members
public string ApplicationName
{ get { return "Hello MEF world"; } }
[Import(typeof(Icon))]
public FrameworkElement MarketPlaceIcon
{ get;
set;
}
[Import(typeof(HelloWorldView))]
public FrameworkElement MainView
{ get;
set;
}
#endregion
}
This is our first encounter with MEF. The first line uses the Export attribute. This class is saying that it is available for someone to use, when someone requests an instance of IMarketPlaceApplication. A bit further, we are using the Import attribute on both the MarketPlaceIcon and the MainView. Here we are saying: MEF, search us a class that’s exporting itself as type Icon and HelloWorldView respectively.
These 2 latter instances will be inserted by MEF upon executing the application, that is, if MEF finds the corresponding export. These exports can be found in the 2 XAML files (in the code-behind). The HelloWorldView.xaml.cs code is shown next. Note the Export attribute: we’re telling to MEF that this type can be used where an Import is requested of the HelloWorldView type.
[Export]
public partial class HelloWorldView : UserControl
{
public HelloWorldView()
{ InitializeComponent();
}
}
The Icon.xaml.cs is pretty similar code-behind-wise (I think I invented that term here): here alse we are adding an Export attribute.
[Export]
public partial class Icon : UserControl
{ public Icon()
{ InitializeComponent();
}
}
The HelloWorldApplication is at this point a stand-alone application (it compiles to its own XAP file), but we’ll now build the Market Place shell that will host this app. The code download at the end of the article contains several sample applications (a Flickr app and a Facebook app).
Similar to a real market place application, our implementation will get a list of apps you purchased previously. Only these are available to you and will be shown. To get this list, I wrote a basic Silverlight-enabled WCF service that fetches this list of available applications. This service is hosted in this case in the hosting website. The code below shows this service, which in this case returns a hard-coded list of apps (note that I have some more apps already added here).
[ServiceContract(Namespace = "")]
[AspNetCompatibilityRequirements(RequirementsMode =
AspNetCompatibilityRequirementsMode.Allowed)]
public class MarketPlaceService
{ [OperationContract]
public List<MefApplication> GetAvailableApplicationsForUser()
{ return new List<MefApplication>()
{ new MefApplication(){ApplicationName="Flickr Image Search", XapFileName="FlickImageSearch.xap"},
new MefApplication(){ApplicationName="Hello World", XapFileName="HelloWorldApplication.xap"},
new MefApplication(){ApplicationName="MEFacebook", XapFileName="FacebookApplication.xap"}
};
}
// Add more operations here and mark them with [OperationContract]
}
[DataContract]
public class MefApplication
{ [DataMember]
public string ApplicationName { get; set; }
[DataMember]
public string XapFileName { get; set; }}
The service uses the MefApplication class as a helper class: it contains the name of the application and more importantly, the name of the XAP file (this could easily be replaced with a Uri to the XAP file).
In the MefMarketPlace, the Silverlight Market Place application, we can create a web reference to this service. In the App.xaml.cs, I add a call to a new method, DownloadMyApplicationList():
private void Application_Startup(object sender, StartupEventArgs e)
{ DownloadMyApplicationsList();
this.RootVisual = new MainPage();
}
This new method makes the service call to get a list of available XAPs that I can use (apps that I purchased).
void DownloadMyApplicationsList()
{ AggregateCatalog = new AggregateCatalog();
container = new CompositionContainer(this.AggregateCatalog);
CompositionHost.Initialize(container);
MarketPlaceService.MarketPlaceServiceClient client =
new MarketPlaceService.MarketPlaceServiceClient();
client.GetAvailableApplicationsForUserCompleted +=
new EventHandler<MarketPlaceService.GetAvailableApplicationsForUserCompletedEventArgs>
(client_GetAvailableApplicationsForUserCompleted);
client.GetAvailableApplicationsForUserAsync();
}
void client_GetAvailableApplicationsForUserCompleted(object sender,
MarketPlaceService.GetAvailableApplicationsForUserCompletedEventArgs e)
{ if (e.Error == null)
{ AvailableApplicationsForUser = e.Result;
InitializeCatalog();
}
}
In the callback method of the service, I call InitializeCatalog(). MEF has the concept of Catalogs: a Catalog can be used to tell MEF where it has to look for Parts. Several types of catalogs exist in MEF for Silverlight: the TypeCatalog, the AssemblyCatalog, the DeploymentCatalog and the AggregateCatalog. A TypeCatalog basically allows us to register a specific type with MEF: if I want MEF to know about a certain Export, I can register it in a TypeCatalog. An AssemblyCatalog tells MEF to look for parts in a specific assembly. The DeploymentCatalog allows us to specify a XAP file and MEF will look in the assemblies therein for parts. It also allows us to asynchronously download a XAP file. An AggregateCatalog can contain any number of other catalogs and more catalogs can be added at any time.
By default, if we don’t specify a Catalog for our application, MEF looks at the current XAP file and for each assembly it finds, it creates an AssemblyCatalog. It then combines these with an AggregateCatalog. That means that we can omit creating a catalog in our application: in this case, MEF will create a default one for us, with something similar to this code:
void InitializeCatalog()
{ AggregateCatalog catalog = new AggregateCatalog();
foreach (var deployedPart in Deployment.Current.Parts)
{ StreamResourceInfo resourceInfo =
Application.GetResourceStream(new Uri(deployedPart.Source, UriKind.Relative));
Assembly assembly = deployedPart.Load(resourceInfo.Stream);
catalog.Catalogs.Add(new AssemblyCatalog(assembly));
}
CompositionHost.Initialize(catalog);
}
Back to our application. If we look at the available catalogs in MEF, we can see that the DeploymentCatalog is a good candidate for what we need: we can use it to download a XAP file (the application that we want to load). After that, we can add each DeploymentCatalog to an AggregateCatalog. MEF will then make these available in our application and we can run the downloaded applications.
In code, this gives the following:
private CompositionContainer container;
void InitializeCatalog()
{
foreach (var item in AvailableApplicationsForUser)
{ DeploymentCatalog deploymentCatalog =
new DeploymentCatalog(item.XapFileName);
this.AggregateCatalog.Catalogs.Add(deploymentCatalog);
deploymentCatalog.DownloadCompleted += (s, e) =>
{ //extend to give meaningful error handling
if (e.Error != null)
MessageBox.Show(e.Error.Message);
};
deploymentCatalog.DownloadAsync();
}
container.ComposeParts(this);
}
You can see that I use a CompositionContainer here. The container is well, like the word says it, a container where MEF puts all the parts, shakes it up and creates/composes parts.
We now have the code that runs when we start the application: it gets a list of all the applications we can use over the service and then it downloads the XAP files of these apps asynchronously. Each XAP file is downloaded using a DeploymentCatalog and these are added to an AggregateCatalog. This now makes our downloaded applications available to run.
Let’s now take a look at the UI where we’ll run the apps from. The following screenshot shows the UI:
The “Load my apps'” button on the top right will execute a command on the viewmodel that will load all available applications in the ListBox on the left.
When clicking on the “Load app” button, the selected application (here the Flickr app) is loaded:
Clicking the “Home” button unloads the app and returns us to the list screen.
The complete XAML listing can be found in the code download. The most important part is shown below. Note that there’s a ContentPresenter used here and it’s bound to the MainView property of the SelectedApplication. The latter is a property exposed on the viewmodel (see further). If no view/app is selected, this ContentPresenter won’t be visible and we’ll see the default UI again.
<Grid x:Name="LayoutRoot" Background="Black">
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="60"></RowDefinition>
</Grid.RowDefinitions>
<Grid>
...
</Grid>
<ContentPresenter Content="{Binding SelectedApplication.MainView}"> </ContentPresenter>
<Button Grid.Row="1" Content="Home" Margin="10" Background="#FFABE3FF"
Command="{Binding HomeCommand}" BorderBrush="#FF00AAFF" Style="{StaticResource ButtonStyle1}" Width="130" Height="40" HorizontalAlignment="Center"
VerticalAlignment="Center"></Button>
</Grid>
Time to look at the viewmodel now. Probably the most important part here is the ObservableCollection<IMarketPlaceApplication>:
[ImportMany(AllowRecomposition=true)]
public ObservableCollection<IMarketPlaceApplication> Applications
{ get
{ return _applications;
}
}
The ListBox in the UI is bound to this collection and since it’s an ObservableCollection, the UI will reflect changes to this collection. That’s important here, since the list of available apps won’t be known after the shell contacted the service. Note that the collection property is attributed with the ImportMany attribute. This is a sign for MEF that more than one part that is exposing itself with the same Export attribute (same type) is allowed. By default, this isn’t allowed since MEF wouldn’t know which one to use. Here, we want the ImportMany since we know that more than one app will be available and they all need to be exported as an IMarketPlaceApplication. Another important thing to note here is the AllowRecomposition option we used here. AllowRecomposition tells MEF that if during the run of the app more Exports become available for this Import, it’s OK to add them, in other words, to rebuild the composition.
The ContentPresenter in the UI bound to SelectedApplication.MainView. The SelectedApplication property is shown next.
private IMarketPlaceApplication _selectedApplication;
public IMarketPlaceApplication SelectedApplication
{ get
{ return _selectedApplication;
}
set
{ _selectedApplication = value;
NotifyPropertyChanged("SelectedApplication"); }
}
NotifyPropertyChanged is a simple method that raises the PropertyChanged event of the INotifyPropertyChanged interface.
private void NotifyPropertyChanged(string p)
{ if (PropertyChanged != null)
{ PropertyChanged(this, new PropertyChangedEventArgs(p));
}
}
The “Load apps” button in the UI is bound to the LoadAppsCommand. I use the MVVM Light RelayCommand here. In the execute code of the ICommand, I ask MEF to satisfy the Imports of the current class (the viewmodel). This basically tells MEF to look at the catalogs and bring all the Export(typeof(IMarketPlaceApplication)) into the ImportMany.
public RelayCommand LoadAppsCommand
{ get
{ if (_loadAppsCommand == null)
{ _loadAppsCommand = new RelayCommand(
() =>
{ CompositionInitializer.SatisfyImports(this);
loaded = true;
},
() =>
{ if (loaded)
return false;
return true;
}
);
}
return _loadAppsCommand;
}
}
The LoadSelectedApplicationCommand and the HomeCommand respectively set the SelectedApplication property to the selected application in the list or null.
public RelayCommand<IMarketPlaceApplication> LoadSelectedAppCommand
{ get
{ if (_loadSelectedAppCommand == null)
{ _loadSelectedAppCommand = new RelayCommand<IMarketPlaceApplication>(
(a) =>
{ SelectedApplication = a;
}
);
}
return _loadSelectedAppCommand;
}
}
public RelayCommand HomeCommand
{ get
{ if (_homeCommand == null)
{ _homeCommand = new RelayCommand(
() =>
{ SelectedApplication = null;
}
);
}
return _homeCommand;
}
}
With that, we have successfully implemented the MEF Marketplace. As said in the very beginning, this can be extended quite a lot. Add a duplex service and a buying system that pushes a message to the client and trigger the client to download the linked XAP file is a nice way to start. The complete file can be downloaded below.
Enjoy!
Code download: MefMarketPlace.zip (868.99 KB)