This article is compatible with the latest version of Silverlight.
To MEF or not to MEF?
Did you ever wanted to build a modular application? You know when you program against interfaces rather than actual implementation, and the implementation is likely to change anytime? The implementation resides in building blocks and you can just replace these building blocks whenever you want. Or maybe you wanted to build an extensible application that can work nicely with plug-ins. I could go on and on with examples but in general, we can say that we have an application and a couple of modules, extensions, building blocks, whatever, and we just want to ”plug” them into our application, without writing any more plumbing code or applying any modification. We just want it to work!
Of course most of us have already met with these requirements and I can tell you, we had choices. Choices like we could build our own DI system with massive Reflection, or to use some 3rd party frameworks, or maybe just go with Microsoft solutions like the Composite Application Library (includes Unity) by the patterns & practices team.
The Composite Application Library (also know as PRISM) is basically a huge toolbox with solutions for many problems in composite application design and MVVM architecture. It supports Inversion of Control through Unity, it supports modularity and also dynamic loading, communication between modules with event aggregators and MVVM / MVP like architectures, Region Management etc. Personally I think Prism is great and in many scenarios it is definitely the way to go, but in certain situations it might be too much or too complicated to do simple things. If it comes to extensibility then you’re probably better off with pure MEF. Prism also includes tools for MVVM. You might not need that since you may want to use the MVVM Light Toolkit. So you won’t need those bits. Also you really need extensibility support, and a simple, straightforward easy to learn solution.
Here is the good news: It is extremely easy to get started with MEF. Without learning tons of design concepts and architecture abracadabra you can just fire up MEF and dynamic component loading in a minute. In short if you want to build extensible applications, plug-in-like scenarios, MEF suites best..
Well MEF is part of .NET 4.0 and is also present in Silverlight 4.0 so you can leverage composition on both platforms. (I also have to mention the Prism v4 includes MEF)
Basic principles of MEF
The basics of MEF can be summarized in 3 simple words: Export, Import, and Compose.
Export
So we have a... let’s call it a part. In this module, we may have anything, a ViewModel, a Repository, any kind of data source or user control for example. This is what we want to dynamically add to our application during runtime. In order to do that we have to tell MEF that this part is ready to be composed. It wants to be part of the composition. This is done declaratively through an attribute called ExportAttribute.
namespace MEFDemo
{
[Export]
public class SimpleDataSource
{
public SimpleDataSource()
{
//Initialize
...
}
public IEnumerable GetData()
{
//Load data
return ...;
}
}
}
Import
So we have a.... wait a minute! What do we have exactly? Is this the shell, our main application? Well it depends. The importer can be anything. The application shell, another part that may also define an export itself and so on. On the importing side we need to be ready to accept the parts we want to plug in. On a very basic level you can think of it as defining members (connection points) where the dynamically loaded parts can be plugged in. Of course this is not always true, you might go with an imperative approach instead of the declarative import mechanism. So we have to tell MEF where to load the dynamically loaded parts. Importing is done through the ImportAttribute.
namespace MEFDemo
{
[Export]
public partial class MainDataView : UserControl
{
[Import]
public SimpleDataSource DataSource { get; set; }
public MainDataView()
{
InitializeComponent();
}
}
}
Compose
This is the moment when we tell MEF that it’s okay, now we have defined the relationships, our parts are ready to be loaded, we also defined where to load them, now please go and do the actual work and build the composition. This is done through an imperative approach using the CompositionInitializer class
public partial class MainPage : UserControl
{
[Import]
public MainDataView DataView { get; set; }
public MainPage()
{
InitializeComponent();
CompositionInitializer.SatisfyImports(this);
}
}
Now if you want, you can think of MEF as the glue that holds the different parts together. There it is, we are done. Now we can do whatever we want with the loaded components. If you don’t want to get your feet wet, now you can run home and start playing with MEF. :)
Importing Mechanism in MEF
Great! Putting these things together wasn’t so complicated, was it? But how does this work? How does MEF know how to pair the exports and imports? The answers is that it knows it by type. If I export the SimpleDataSource class then MEF can pair it only to an import of SimpleDataSource. But what if I don’t have SimpleDataSource on the importing side? Because on the importing side, since SimpleDataSource implements IDataSource, I work with the interface instead of the actual implementation. (After all this is my final goal, isn’t it?)
Using interfaces as contracts
The solution is to define a contract on the export. This means that on the export attribute you explicitly define what type of part MEF should look for on the importing side. This can be done through passing the type of the export to the export attribute: [Export(typeof(IDataSource))] So on the importing side you don’t have to change anything.
namespace MEFDemo
{
[Export(typeof(IDataSource))]
public class SimpleDataSource : IDataSource
{
public SimpleDataSource()
{
//Initialize
}
public IEnumerable GetData()
{
//Load data
return null;
}
}
}
namespace MEFDemo
{
[Export(typeof(UserControl))]]
public partial class MainDataView : UserControl
{
[Import(typeof(IDataSource))]
public IDataSource DataSource { get; set; }
public MainDataView()
{
InitializeComponent();
}
}
}
Constructors, parameters and importing
What does MEF do in this case? Well it creates instances of the exporting type using their default constructors. Interesting, huh? It works somewhat IoC-ish, doesn’t it? But when I use IoC containers I can use constructors with parameters and I can also inject instances into these params. Now what about MEF? Well, please keep in mind, MEF is not an IoC framework but it does support this functionality. As a matter of fact you can tell MEF which constructor it should invoke when composing, this is done through the ImportingConstructorAttribute. In the code below we also added the ImportAttribute to the IDataSource parameter. You should note that this is not required. If you don’t apply the attribute, MEF will still load the relating part when composing. However if the ImportAttribute needs parameters like contract information, then you should definitely decorate the parameter.
namespace MEFDemo
{
[Export]
public class MainDataViewModel
{
IDataSource dataSource;
[ImportingConstructor]
public MainDataViewModel([Import] IDataSource dataSource)
{
this.dataSource = dataSource;
}
}
}
[Export(typeof(UserControl))]
public partial class MainDataView : UserControl
{
[Import]
public MainDataViewModel ViewModel { get; set; }
public MainDataView()
{
InitializeComponent();
}
}
The above example loads the ViewModel through MEF. But the ViewModel also needs an IDataSource instance as an input, so it looks around and finds a concrete implementation, in this case the SimpleDataSource, which will be used for composition.
Importing Many different implementations of the same contract
MEF does provide you a great deal of flexibility when it comes to putting the pieces together. But what happens when you have too many candidates for one spot? For example an instance of IDataSource should be imported. Well, MEF looks around to find out that there are actually two or more instances being exported with the contract type IDataSource: SimpleDataSource and ComplexDataSource. So if you run it, you’ll get something like this:
System.ComponentModel.Composition.ChangeRejectedException: The composition remains unchanged. The changes were rejected because of the following error(s): The composition produced a single composition error.
Now the thing is that MEF can’t make this decision for you so you’ll get an exception while composing. You are the one who has to make this decision. So you’ll have to let MEF import both parts so you can choose between them. To enable this behavior you have to slightly modify the importing code. You have to use the ImportManyAttribute and apply it on an IEnumerable property. In the case of the example above, you should have an IEnumerable<IDataSource>.
namespace MEFDemo
{
[Export(typeof(IDataSource))]
public class ComplexDataSource : IDataSource
{
public ComplexDataSource()
{
//Initialize
}
public IEnumerable GetData()
{
//Load data
return null;
}
}
}
namespace MEFDemo
{
[Export(typeof(UserControl))]]
public partial class MainDataView : UserControl
{
[ImportMany(typeof(IDataSource))]
public IEnumerable<IDataSource> DataSources { get; set; }
public MainDataView()
{
InitializeComponent();
}
}
}
Using String Contracts
What if you do have two exports with the same type. But they are used in a totally different way, which means putting them in a common IEnumerable container is not satisfying. Let me give you an example: You have two UserControls. Both of them is exported with the type UserControl.There is nothing common in the those two. Maybe they are in different assemblies as well. But in the shell you have two properties of type UserControl. One is the MainView, another is the DetailsView or something like that. In the shell you want to handle them differently and you want to be able to make a difference between those two. One of your options is to change the contract. Instead of saying you are exporting typeof(UserControl), you may say you import ”MainView” and also you export ”MainView”. The same goes for the DetailsView. Using string contracts provides you a great deal of flexibility if it comes to importing.
namespace MEFDemo
{
[Export("MainView")]
public partial class MainView : UserControl
{
public MainView()
{
InitializeComponent();
}
}
}
namespace MEFDemo
{
[Export("MainView")]
public partial class MainView : UserControl
{
public MainView()
{
InitializeComponent();
}
}
}
namespace MEFDemo
{
public partial class MainPage : UserControl
{
[Import("MainView")]
public UserControl MainView { get; set; }
[Import("DetailsView")]
public UserControl DetailsView { get; set; }
public MainPage()
{
InitializeComponent();
PartInitializer.SatisfyImports(this);
}
}
}
Importing functions
The last trick I want to show you in this article is importing logic. So far you imported classes. But what if you don’t need all that? You just want to import some function? Maybe you have a filtering algorithm and all you need is to get that code and have the ability to change it anytime. Luckily for you, MEF addresses this issues as well. Through function importing you can define Func<> delegates as importing points and simple export functions using the Export and Import attributes. After you have the import you can invoke your method both synchronously and asynchronously. Pretty cool, huh?
namespace MEFDemo
{
public class SpecialAlgo
{
[Export]
public IEnumerable DoTheFiltering(IEnumerable items)
{
//Complex filtering :)
return items.Cast<string>().Take(2);
}
}
}
namespace MEFDemo
{
public partial class MainPage : UserControl
{
[Import]
public Func<IEnumerable, IEnumerable> FilterFunc { get; set; }
public MainPage()
{
InitializeComponent();
CompositionInitializer.SatisfyImports(this);
}
private void button1_Click(object sender, RoutedEventArgs e)
{
List<string> items = new List<string>{"Zoltan Arvai", "Silverlight 4", "MEF Intro"};
var result = FilterFunc.Invoke(items);
}
}
}
You might be wondering now why I didn’t use generics since this example is basically screaming for it. The reason is simple. At the time of this writing MEF does not support generics. Too bad but this limitation is not only for function exports but also for classes. It’s just something we have to live with right now. (In the MefContrib open source project there is a catalog called GenericCatalog, that supports this scenario.)
Summary
These capabilities you can be fired up in a very few minutes. As you’ve seen MEF provides you a very special way of importing parts into your application. It’s not trivial to determine its exact position in the full .NET ecosystem, to tell you the truth lot of arguments were made on both sides, since it definitely has some overlapping with other technologies. Finally Microsoft found its place and integrated it with Prism. I think of MEF as a lightweight alternative for building modular and extensible application. Hopefully by now, you have a solid understanding what MEF can do for you on a very basic level and maybe you can make a decision whether you want to go with MEF or with something else.