Simple Example of Managed Extensibility Framework (MEF) in Silverlight


As you may have heard, we recently shipped MEF support of Silverlight in our CodePlex drop..  I wanted to give you a very simple introduction to MEF and how to use it in Silverlight.   This example will show how to use lose coupling, dependency injection and delay loading of components.   This is also an update to my Simple MEF example from a few months ago as just about everything here applies to WPF, WinForms and ASP.NET apps as well. 


The demo requires (all 100% free):



  1. VS2008 SP1

  2. Silverlight 3 RTM

  3. MEF’s July CodePlex drop

Also, download the full demo files


Let’s start with the very cool Silverlight Navigation Application


image


Setting up The Problem


This is a very simple example just to show how the technology works.  Let’s say you want to put some string a TextBlock… As a bigger example, think of pages in an application or components in a portal, etc, etc.


Replace the contents of the ContentStackPanel in Home.xaml with a ListBox and set up some binding.



<StackPanel x:Name=”ContentStackPanel”>
 
    <TextBlock Text=”{Binding Mode=OneWay}”></TextBlock>
 
</StackPanel>

Then in codebehind we set up the datacontext:



public Home()
{
    InitializeComponent();
    LayoutRoot.DataContext = “Hello World!”;
}

Of course, we get exactly what we’d expect…. 


Now there are some problems with this.. For example, the value of the string is tied up in the constructor, i might want to have that factored out so that it can be accessed separately. 



   1: public partial class Home : Page
   2: {
   3:     public Home()
   4:     {
   5:         InitializeComponent();
   6:  
   7:         var message = new SimpleHello();
   8:         LayoutRoot.DataContext = message;
   9:     }
  10: }
  11:  
  12: [Export(“Message”)]
  13: public class SimpleHello
  14: {
  15:     public override string ToString()
  16:     {
  17:         return “Hello World!”;
  18:     }
  19: }

This will certainly do the trick at some level, but there is still something odd about lines 7 and 8… I am creating an instance of exactly this type which locks the functionality down to one instance.  That means the type has to be in my codebase.  What if I’d like to enable some separation?  maybe get that Message from a variety of sources based on config, the user preference, the role of the user, etc.


Enter MEF


Let’s see how MEF can help..  First we need to add a reference to the MEF assembly (System.ComponentModel.Composition.dll) that is found in the MEF_Preview_6\bin\SL3 folder of the latest bits.  I copied it into the bin directly of the project (which is hidden by default) and added a reference to it from there. 


As Jason Olson says: MEF is as easy as 1, 2, 3…Export It, Import It, and Compose It…


So the first step is Export it..  so let’s export the SimpleHello type… this is easy enough to do by simply putting an Export attribute on the type and specifying the contract name.



   1: [Export(“Message”)]
   2: public class SimpleHello
   3: {

Next step is to Import it, so let’s import  some type to databind to.



[Import(“Message”)]
public object Message; 
public Home()
{
    InitializeComponent();
 
    LayoutRoot.DataContext = Message;
}

That looks very clean… I simply say what I have (an export) and what i need (an import).   But who does the wiring up?  Well, we have one more step… Compose It:


Add the following lines to the constructor…



   1: var catalog = new PackageCatalog();
   2: catalog.AddPackage(Package.Current);
   3: var container = new CompositionContainer(catalog);
   4: container.ComposeParts(this);

Line 1 shows off our new PackageCatalog that just new for this Silverlight release.  Catalogs generally tell MEF where to look to find stuff to put in the container.  Line 2 adds the current XAP to the catalog.. later we will show how to add XAPs that are asynchronously downloaded via a different catalog. 


Line 3 creates  a Composition container– this is effectively the container that all the different parts will be wired up together.


Line 4 composes… that is wires up all the imports and exports. After this line, all imports are fully satisfied or an exception is raised.


Running the app has it work exactly the same way, but now loosely coupled.


image


That is great, but using strings such as “Message” to identify contracts is fraught with problems.  It turns out the CLR already has a pretty well developed way to deal with contracts and that is CLR Types.  So it is recommended in most cases that you use CLR Types to indicate the contracts.  To do this, let’s define an IMessage interface in a separate assembly so that it can be shared by different assemblies contributing components. 


Add a new project, and call it ContractsClassLibrary


image


Add a single type.. IMessage… right now it has no members, it is effectively a marker interface.  We could of course define some methods if they are needed.



namespace ContractsClassLibrary
{
    [InheritedExport]
    public interface IMessage
    {
 
    }
}

Notice we put the new InheritedExport attribute on this type… this means that any type that implements this interface will automatically be exported as type IMessage.  This keeps the “MEF goo” out of your public object model.


Now, add a reference to ContractsClassLibrary from the MyMEFApp project and let’s look at how that SimpleHello type changes..



public class SimpleHello : IMessage
{
    public override string ToString()
    {
        return “Hello World”;
    }
}

Notice, no MEF goo on it… 


Fun and the app and you get the exact same results… but this time our contract is a CLR type rather than a string. 


image


Now, let’s say I had more than one message to show..  No problem, i just add another instance to the container with the same export. 



public class SimpleHola: IMessage
{
    public override string ToString()
    {
        return “Hola”;
    }
}

Hit F5 and… Wham.. I get an error..


image



(Side note: if you get a less helpful message that says “navigation failed”, in MainPage.cs change the ErrorWindow to show the inner exception…)



private void ContentFrame_NavigationFailed(object sender, NavigationFailedEventArgs e)
{
    e.Handled = true;
    ChildWindow errorWin = new ErrorWindow(e.Exception.InnerException);
    errorWin.Show();
}

As these things go, it is actually a pretty helpful error message:


The composition remains unchanged. The changes were rejected because of the
following error(s): The composition produced a single composition error.
The root cause is provided below. Review the CompositionException.Errors
property for more detailed information.

1) More than one exports were found that match the constraint
‘((exportDefinition.ContractName = “ContractsClassLibrary.IMessage”)
&& (exportDefinition.Metadata.ContainsKey(“ExportTypeIdentity”) &&
“ContractsClassLibrary.IMessage”.Equals(exportDefinition.Metadata.get_Item(“ExportTypeIdentity”))))’
.

Resulting in: Cannot set import ‘MyMEFApp.Home.Messages (ContractName=”ContractsClassLibrary.IMessage”)’ on part ‘MyMEFApp.Home’.
Element: MyMEFApp.Home.Messages (ContractName=“ContractsClassLibrary.IMessage”) –> MyMEFApp.Home


at System.ComponentModel.Composition.CompositionResult.ThrowOnErrors(AtomicComposition atomicComposition)
at System.ComponentModel.Composition.Hosting.ComposablePartExportProvider.Compose(CompositionBatch batch)
at System.ComponentModel.Composition.Hosting.CompositionContainer.Compose(CompositionBatch batch)
at System.ComponentModel.Composition.AttributedModelServices.ComposeParts(CompositionContainer container, Object[] attributedParts)
at MyMEFApp.Home..ctor()



Basically it is saying that we were only expecting one message, and the container has more than one.. 


The easy solution here is to accommodate more than one Message..

 

[ImportMany]
public ObservableCollection<IMessage> Messages { get; set; }


and let’s change the UI control to a ListBox…



<ListBox ItemsSource=”{Binding Mode=OneWay}”></ListBox>

Run it and we get both messages..


image


Another thing that is really cool about MEF is that we do full composition, that is even the parts in the container can have dependencies that are satisfied and runtime.   For example, let’s take out SimpleHello class and say we wanted to externalize providing the actual text… we could do that easily enough.



   1: public class SimpleHello : IMessage
   2: {   
   3:     [Import(“Text”)]
   4:     public string Text { get; set; }
   5:     public override string ToString()
   6:     {
   7:         return Text;
   8:     }
   9: }
  10:  
  11: public class TextProvider
  12: {
  13:     [Export(“Text”)]
  14:     public string Text { get { return “Hello World!”; } }
  15: }

We simply export the text from a provider class and import it into our SimpleHello class. (I am using the string contract name here just for simplicity, you could of course define an IText interface and use it exactly as we showed above.)   Notice the by product of this pattern is that each class gets very focused and specialized in what it deals with.  SimpleHello now is just about overriding ToString() and doesn’t care a thing about where it gets the message from.   That means we could easily add another way to offer text for binding… How about as a button?



   1: public class ButtoHello: Button, IMessage
   2: {
   3:     [Import(“Text”)]
   4:     public string Text {
   5:         get { 
   6:             return this.Content.ToString();
   7:         }
   8:         set
   9:         {
  10:             this.Content = value;
  11:         }
  12:     }
  13: }

This is time, we use the same text, but rather then ToString(), we use it to set the content property of the button.  This is a great example of a single instance exporting and importing dependencies. 


image


OK – that is cool… but all this is in the same project.. what if we wanted a bit more separation?   Well, the first step we could do is put some parts into a separate assembly, but deployed with the same XAP. 


image


We will need to reference our ContractsClassLibrary project.


Then just add a couple of classes that export “Message”



public class Class1 : CheckBox, IMessage
{
    public Class1()
    {
        this.Content = “From Assembly: ma kore?”;
    }
}
 
public class Class2: IMessage
{
    [Import(“Text”)]
    public string Text { get; set; }
 
    public override string ToString()
    {
        return “From Assembly:” + Text;
    }
}

Notice, we can again, import the text optionally if we’d like.  This shares the exact same instance with any other type that imports it. 


Then we add a reference to this library from the main Silverlight app… this puts the library in the XAP


image


Now, run it and we get some more items.. 


image


Now the final step is to load the parts, asynchronously from the server.. This allows you to have components that are downloaded ONLY when they are needed.  It also enables much faster startup time where the core of the app can start up and features can light up as they are downloaded.  This is a much better experience than a long “loading…” screen.   


To do this, we need to create a library that is packaged as a XAP.. the best way to do that is to create a new Silverlight Application, and just delete the MainPage.xaml… 


image


Then we want to host this in the same web site.. .Notice you could host it in a different website, but you would then need to use the Silverlight networking stack’s mechanism to get at non-originating servers. 


image


You can go ahead and delete MainPage.Xaml and App.Xaml so we don’t get confused and add a Class1.cs file.


image


We will also need to add a reference to our ContractsClassLibrary project


Then just define a class an Export it.. 



public class Class1: IMessage 
{
    public override string ToString()
    {            
        return “From Dynamically Loaded: ciào”;
    }
}

You could optionally import the same Text property if you’d like as well.. 



public class Class2 : ComboBox, IMessage 
{
    [Import(“Text”)]
    public string Text
    {
        set
        {
            this.ItemsSource = value.ToCharArray();
        }
    }
}

Now we need to go back into the main app and tell it where to dynamically load this from.



   1: public Home()
   2: {
   3:     InitializeComponent();
   4:  
   5:     var catalog = new PackageCatalog();
   6:     catalog.AddPackage(Package.Current);
   7:  
   8:     Package.DownloadPackageAsync(
   9:         new Uri(“DynamicallyLoadClassLibrary.xap”, UriKind.Relative),
  10:        (sender, pkg) => catalog.AddPackage(pkg) 
  11:     );
  12:  
  13:  
  14:     var container = new CompositionContainer(catalog);
  15:     container.ComposeParts(this);
  16:  
  17:  
  18:     LayoutRoot.DataContext = Messages;
  19: }

As you can see, we inserted lines 8-11 to deal with this new dynamically loaded XAP.  Here we are simply doing delay loading, but you could wait and load on some user action (clicking a button for example) or you could load based on who is logged in, what functionality they prefer, what role they are in, etc. 


In line 9, we create a URI pointing to our XAP.. in this case from the same server, but it could be from any server assuming the right policy files are in place. 
In line 10, we are handling the callback.. remember this is an async call.  When the call completes, we simply add any parts discovered to the catalog.


Now, the async nature of this is interesting, because effectively we are changing a programs dependencies mid-flight.  Not always a good idea, so it is something you need to opt into.   



[ImportMany(“Message”,AllowRecomposition=true)]
public ObservableCollection<object> Messages { get; set; }

And now we run and it looks great!


image


So, what have we seen?  You can use MEF to improve the quality and structure of your code so that classes have a single set of responsibilities.  MEF also makes it easy to optionally download components on demand. 


Check out the completed example


We’d love to hear what you think!

Comments (13)

  1. Michel Bergeron says:

    Can you talk about difference between MEF and Prism for Silverlight ? There is a lot of differents kinds of frameworks for Silverlight now and it is difficult to know the differences and when to use one or another….

    Thank you

    Michel

  2. Hi,

    I think I need to delve into MEF a little bit more as I cannot understand the concept you are telling.

    You can be little bit clear .

    Thanks,

    Thani

  3. ElemarJr says:

    Congratulations. Very nice introduction about how to use MEF with Silverlight!

  4. gblock says:

    Hi Michael

    Prism is a set of guidance coming out of patterns & practices for building composite UI applications, that is applications that are deployed in separate modules where each module represents a different sub-system such as Order Entry, Reporting, Accounting, etc. Prism also includes a set of additional services such as the RegionManager and EventAggregator which aid in building such apps.

    MEF is a general composition technology in the framework that assembles components pulling their dependencies from a myrida of different sources, including XAP files for Silverlight apps. MEF is not UI specific and can be used both in UI and non-UI applications.

    As far as whether to use Prism or MEF, long term I’d say you e that you can use both together, as the two technologies complement one another.  We are working with patterns & practices, to provide better integration with Prism going forward.

    Today, the answer is not as straight forward. In general I would give these guidelines.

    1. If you are building a composite application, with multiple modules that internal teams will be maintaining, then I would recommend using Prism.

    2. If you building a Silverlight application that you want to allow third-parties to customoize and extend, through adding their own capabilities after the application has been deployed, then use MEF.

    HTH

    Glenn

  5. Michel Bergeron says:

    Thank you Glenn for the precisions.

    Last question, does MEF is supported by Microsoft ?

    Michel

  6. bill simons says:

    Can you use mef in a commercial application

    or will that come later on??  

  7. gblock says:

    Michel, Yes, MEF ships as part of the .NET Framework and is fully supported. The releases on CodePlex are previews of what is to come in the framework.

    Bill, Yes you can, MEF ships on Codeplex under an MS-PL license thus you can use it without a "go-live" license.

  8. Michel Bergeron says:

    Thank you for the answer Glenn  :))

  9. bill simons says:

    Thank you for your reply. I would love to use this a

    asp.net mvc wcf restful web application. This is what

    I have been searching for in doing  very simple basic

    paragraph development…..        

  10. bnaya says:

    Seem great i will check it soon

  11. niblumha says:

    Nice post Brad!

    A simple but handy tip mentioned in the video here (http://development-guides.silverbaylabs.org/Video/Silverlight-MEF): you can decrease the size of DynamicallyLoadedClassLibrary.xap by setting ‘CopyLocal’ for the System.ComponentModel.Composition reference to ‘false’.

    >> And now we run and it looks great!

    I like your code more than your UI design 😛

  12. Kanary says:

    Thank you Brad for you helpful posts!

    I load xamls from different modules. When I click some button on one page I need to send additional information from this page to another and react to this event on the second page. How can I do it with MEF?