Introduction
This is the year all .NET developers will be licking there lips at the excitement and anticipation around yet another version release of our beloved framework of choice.
So in the spirit of all things new and exciting. Today i'll be discussing one of my favourites MEF. We all know about MEF's sheer ability to bring about simplicity in implementation, in a development environment defined by complexities, on a day to day basis. Firstly I will be discussing the key features that have been added to MEF2 so far, that I think will make a massive impact upon the release of .NET 4.5. However please note this is more of a sneak peek and not all of what I show you will be in the final version. At time of writing this article the current MEF 2 version is Preview. The new features that will be discussed include The ExportFactory<T>
and the new registration API called the RegistrationBuilder
to name a few. So let's dive in.
Background
This is a beginners' guide to quickly get you familiar to some of the key changes that have been implemented in MEF 2. So you can start using the preview version straight away with no additional research and understanding.
Setting it all up
Firstly for those of you who have already used the first iteration of MEF, you will have noticed a few distinct differences between the first release and the new upcoming release. One of the subtle changes is all the common export catalogs; now contain an additional constructor overload. This parameter argument is for a new class called theRegistrationBuilder
. This class handles the registration of all your exports and part creation through the RegistrationBuilders rich API. So you no longer need to worry about placing attributes on all your dependencies. This was a great move by the team who developed MEF, because MEF’s main role is to provide an easy implementation of dependency injected types for loosely coupled architecture and extensible projects. Any developer extending the functionality of a project doesn’t have to now worry about setting up attributes on the objects he or she wishes to inject. Let’s jump into an example setup below; As you can see in the code snippet below MEF is more flexible with its object lifetime management, as well as the other new features I mentioned above. Now that you are completely bored with me rambling on let me show you how the container and a simple export is set up.
var convention = new RegistrationBuilder();
convention.ForTypesDerivedFrom<igreetings>().Export<greetings>();Colourised in 0ms
As you can see we instantiate the new
RegistrationBuilder
class and then use its Fluent API to map the dependency. In this simple case, a concrete type that implements an interface is being exported.
For those of you who haven’t used MEF 1 the equivalent would be the following in MEF 1.
[InheritedExport] public interface IGreetings
{
void Greet(string name);
}
public class Greetings : IGreetingsColourised in 1ms
Now registering the container would be as follows.
var assemblyCatalog = new AssemblyCatalog(Assembly.GetExecutingAssembly(), registeredExports);
var catalog = new AggregateCatalog(assemblyCatalog);
container = new CompositionContainer(catalog,
CompositionOptions.DisableSilentRejection | CompositionOptions.IsThreadSafe);
container.ComposeParts(this);Colourised in 2ms
Note that we now pass in the RegistrationBuilder
’s instance variable
registeredExports
to our assemblyCatalog
’s constructor. And then the rest of the process is virtually the same as MEF 1. There is one more line that needs to be discussed though. The
CompositionContainer
’s constructor contains an overload for an enumeration of CompositionOptions
when composing parts.
container = new CompositionContainer(catalog, CompositionOptions.DisableSilentRejection | CompositionOptions.IsThreadSafe);Colourised in 0ms
Available Options are:
CompositionOption | Description |
Default | Is
the default implementation and settings. |
DisableSilentRejection | Shows
more detailed exceptions when an import/export fails. |
IsThreadSafe | Composes
the exports in a thread safe manner. |
ExportCompositionService | Sets
the Export composition service. |
The reason for these options is to better manage the composition of the catalogs parts as well as provide more informative exceptions to better diagnose failed exports. This by the way was a nightmare with MEF 1. As you may have already noticed MEF 2 is far more flexible in the way exports can be set and imported. So let’s focus our discussion on that now and dissect the RegistrationBuilders API to further understand how exports are registered and imported into types and finally consumed by the container.
Registering Types the Flexible Way
MEF has three ways of going about registering a particular type and exporting it.
-
ForType()
& ForType<>()
: Allows you to specify any type that you wish to export either by way of it’s known type at compile time using the generic method. Or by way of passing in a type of an object that is only known at runtime.
convention.ForType<test>()Colourised in 0ms
-
ForTypesMatching()
& ForTypesMatching<>()
: Allows you to export types based on a predicate filter.
convention.ForTypesMatching(x => x.Name.EndsWith("Exam")).Export();Colourised in 0ms
-
ForTypesDerivedFrom<>()
& ForTypesDerivedFrom()
: Allows you to specify a base class or interface that an object inherits from and then exports it. This is the same as using InheritedExport
in MEF 1. This is the preferred and most extensible approach when exporting types. This is because it resolves any concrete types that implement the specified interface or inherit its base class. This ultimately means you don’t have to specify the concrete type even when registering the export. MEF will do that automatically.
convention.ForTypesDerivedFrom<IGreetings>().Export<IGreetings>(); Colourised in 0ms
Working with the API
We’ve taken a brief look at what each method does for registering a type as an export in MEF. Now let’s take that theory and implement it into practice. I’ve created a simple project that I’ve supplied in this article called Learning.MEFII.Console.Exams
. The projects class structure is as the following.
The basic scenario is a learner that writes particular exams based on whether they have source material supplied with the exam. This example will illustrate how you can use the ForTypesMatching()
method to export and import certain objects based on their type information. As well as a brief look at importing a collection of exports.
class Program
{
public CompositionContainer container;
static void Main(string[] args)
{
var p = new Program();
p.RegisterExports();
var exams = p.container.GetExportedValue<learner>();
}
public void RegisterExports()
{
var builder = new RegistrationBuilder();
builder.ForType<learner>().Export<learner>();
builder.ForTypesMatching
(x => x.GetProperty("SourceMaterial") != null).Export<exam>();
InitializeMef(builder);
}
public void InitializeMef(RegistrationBuilder registeredExports)
{
var assemblyCatalog =
new AssemblyCatalog(Assembly.GetExecutingAssembly(), registeredExports);
var catalog = new AggregateCatalog(assemblyCatalog);
container = new CompositionContainer(catalog,
CompositionOptions.DisableSilentRejection | CompositionOptions.IsThreadSafe);
container.ComposeParts(this);
}
}Colourised in 10ms
In the code sample above you can see in the main class Program
we register the container as before and a simple export called Learner
. However there is a second registered export that is registered in a very different manner. And that is the exportation of the Exam objects.
builder.ForTypesMatching(x => x.GetProperty("SourceMaterial") != null).Export<Exam>();Colourised in 1ms
You can see that I am only exporting classes that contain the property SourceMaterial
. This is a very naïve scenario on how you would determine certain exports based on criteria in a real world application. But this is just a simple example illustrating MEF 2’s ability to filter certain exports. Think of it as LINQifying your IOC container.
Syntactic sugar the cherry on MEF’S cake
The most noticeable bit of flexibility in MEF2 is the addition of predicate filters right throughout the RegistrationBuilder'
s API as well as the extensive use of chained methods that logically relate to each step of the configuration process to register your desired export. Most of MEF’s lambda expressions relate to .nets built in reflection library which should been seen as an advantage to anyone using MEF. It’s because it solves the problem of learning a whole new reflection library to manipulate MEF’s exports. As I showed in the example above most of the lambda expressions pass in a System.Type
argument and returns a Boolean
result based on specified criteria. So any type that returns true based on your filter will generate an export. This is a very powerful option to have. It provides you with a far more granular approach to dependency injection. Let’s illustrate this point further with how we can pick what constructor is initialized when an export is imported in MEF.
Put on that hardhat for some Object Construction
Let me paint a picture for scenario below. The learner has just started high school and will not write an exam until the next term. However the learner has enrolled to study geography and he or she needs a teacher to teach them. So the object looks as follows.
public Learner(IEnumerable<Exam> exams)
{
Exams = exams;
Name = "Jack";
LastName = "Sparrow";
}
public Learner(IEnumerable<Educator> teacher)
{
Teacher = teacher.OfType<Teacher>().First();
}Colourised in 4ms
There are two constructors with the same number of parameters. Except for one difference, the learner either just has a teacher to learn a particular subject or is enrolled to write exams. Now what happens if we have an instance of a learner?
A Composition error occurs because MEF cannot decide which constructor to use to initialize the learner object. So how do we go about determining which constructor should be used. The RegistrationBuilder
’s API has a method called SelectConstructor()
that takes a lambda expression to determine the constructor to be used for the objects initialization. So the code is as follows.
Func<ConstructorInfo[], ConstructorInfo> constructorFilter
= x => x.First(z => z.GetParameters()
.First().ParameterType == typeof(IEnumerable<Educator>));
builder.ForType<Learner>().SelectConstructor(constructorFilter).Export<Learner>();Colourised in 2ms
Above we call the SelectConstructor()
method and pass in a lambda that accepts an array of ConstructorInfo
and returns the correct constructor based on the filter. So in this example we are selecting the first constructor that has a parameter that is of type IEnumerable
of Educator
and then return it in the lambda expression. Thus the result is the correct constructor is called.
Another important thing to note is that if a particular base type is implemented by more than one type it can easily be imported into an objects constructor by just passing it in as an IEnumerable
of your designated base type. The great thing about this is you don’t need to do any further configuration in the API to get this to work. There are a few other things mef will do for you straight out the box. To start off when you inject imports into an object which has multiple constructors the one with the most parameters will be selected for constructing the object. Lazy loading can also be done without configuration all you have to do is follow the requirements for a lazy loaded import. And that is done by wrapping the type in a Lazy of T object. Let me show you an example of this below.
There you have it all works by default just by following the conventions I’ve discussed, and with a minimal bit of code being written.
builder.ForType<Learner>().Export<Learner>();
builder.ForTypesDerivedFrom<Educator>().Export<Educator>();Colourised in 0ms
The benefits of being Lazy
The first question to be asked that I showed you in the previous example is. What is the Lazy of T class? And how does it benefit me? Lazy of T is a wrapper class on a type that delays the instantiation of an object until it is needed for use. We all wonder how we can often improve the performance of our applications by minimizing expensive calls to objects or caching information to limit the number of calls to a particular object without instantiating a new instance each time it’s being called. Yes one can create a static singleton of an instance of an object and call it throughout the lifetime of the application. But what happens in the event that an object is only ever called in certain scenarios. For example an application that supports plugins, you should only instantiate the plugin that has been selected by the user not all of them at application startup. A resource should be instantiated only when required. The problem with instantiating all objects regardless of whether they will be used or not is you’ll always have unnecessary objects hanging around in memory and this in efficient and resource intensive.
This is where the Lazy<T>
class solves this problem without you having to write a singleton object and then writing some logic to handle the delay of an object being initialized in a thread safe manner. This is all done for you just by wrapping the type in the Lazy<T>
generic parameter. How does Lazy of T work? Lazy<T>
has two main properties Value
and IsValueCreated
. The first time the Value
property is called an instance of the object is created by using the Activator.CreateInstance()
method to dynamically instantiate the object. Thereafter every call to Lazy<T>.Value
the currently cached instance is called. The object therefore is only initialized once and IsValueCreated is set to true. A few considerations need to be made when using the Lazy<T> class. Reflection may make your code more flexible and dynamic but it all does come at a cost. All the details related to reflection is only known at runtime so any task you do using reflection is always going to be slower than a direct implementation or call at compile time.
In this scenario a direct call to:
Exam exam = new Exam();Colourised in 0ms
will always be quicker than
Activater.CreateInstance(typeof(Exam));Colourised in 0ms
That being said MEF’s instantiation of all its types is based at runtime so in this scenario all exports are going to be composed at run-time so it makes no difference to pass your imports as Lazy<T>
objects. One final unrelated note if you are calling an instance of Lazy<T>
in its constructor you can specify how you want a particular object to be initialized.
For example
Lazy<Learner> lazyLearner = new Lazy<Learner>(()
=> new Learner(p.container.GetExportedValues<Educator>().OfType<Teacher>().First()));
var learner = lazyLearner.Value;Colourised in 3ms
There you have it the same result as before but controlling
which constructor is used to instantiate the object when calling the Value
property. There is another overload that can control the objects thread safety
as well by just passing in a Boolean value.
Object Lifetime
In the last few sections we’ve learnt how to construct instances of an object with the import and export api of the RegistrationBuilder with immediate injection as well as deferred injection by way of Lazy<T> implementations. But what about the lifetime of these newly created instances? And how will they be managed? Well let’s address that issue now by turning our focus to the importance of the lifetime of these newly created instances. This is often a neglected thought when dealing with your inversion of control containers and dependency injection, because let’s face it there are those certain scenarios where by creating a singleton of an object is unnecessary and resource intensive.
How the PartCreationPolicy works
In MEF1 you would handle part creation with an attribute on your export. So that when that object is imported in another exported object a singleton of that object would be returned by default. However if you explicitly set the partcreationpolicy to NonShared
each time the object was imported a new instance was created. Let’s open the project Learning.MEFII.Console.ObjLifetime
to show an illustration of this. The scenario is as follows a LifetimeManager object loops through 4 calls to the exported object the ObjectTester
and sets its counter property and then returns the result.
public class ObjectTester
{
public int Counter { get; set; }
public ObjectTester()
{
}
}
public class LifeTimeManager
{
public void ShowObjLifetime(CompositionContainer container)
{
for (int i = 1; i < 5; i++)
{
var tester = container.GetExportedValue<ObjectTester>();
++tester.Counter;
System.Console
.WriteLine("execution {0} Counter Value is {1}", i,tester.Counter);
}
}
}Colourised in 9ms
Note
the results above show you that no matter how many times the ObjectTester
import is called from the container it is never being constructed again after its
first time it was instantiated. That is why the counter value increases every
time because by default you are always using the same instance. How can we
change this? Again we turn to the RegistrationBuilder
’s API and after the
Export()
method you specify the SetCreationPolicy()
method. And set its
creationPolicy enumeration to NonShared
. Like so:
And
now we have our desired result a fresh instance every time an import is called
in the loop. This is achieved by just changing a single line of code. This
ultimately allows you to not have to worry about changing your code or adding
an attribute like in MEF 1.
To Share or Not to Share
We know MEF2 has the support to alter an objects lifetime but in what scenarios is it useful. And why would we want to override its default behavior of importing singletons into dependent objects? Firstly the most common scenario is DbContexts. When you want a repository to have a new instance of the DbContext
each time you execute a query with the database. However what if you want to control when that instance must be instantiated and then disposed of?
The ExportFactory<t>
The ExportFactory<T>
gives you better control over an objects lifetime. When you require the instance to be generated and when you want to dispose of that instance. Instead of having the object generated when the parents object is generated you can gain access to the instance only when needed. Like Lazy<T>
for example except you can dispose of the instance once execution is done. This is sort of like a scoped import for a unit of work. Let’s look at the example below on how this can be used in a mock db query example. The projects structure looks like the following.
What we have above is a simple project mocking an
implementation of a repository that gets data out of a DbContext
like the
entity framework does except the data source in this example is hardcoded.
public class PersonRepository<TEntity> : IRepository<TEntity>
where TEntity : class, IPerson
{
public ExportFactory<IMockDbContext> DbContext { get; set; }
public PersonRepository(ExportFactory<IMockDbContext> dbContext)
{
DbContext = dbContext;
}
public TEntity GetByAge(Func<IPerson, bool> filter)
{
using (var ctx = DbContext.CreateExport())
{
return ctx.Value.MockPersonDbSet.AsEnumerable().SingleOrDefault(filter) as TEntity;
}
}
}Colourised in 8ms
The first important thing to note above is the the IMockDbContext
object is wrapped in a ExportFactory<T>
object and then injected into the Person Repository class.
And then when GetByAge
method is called. A using statement is wrapped around the ExportFactory<T>
type and CreateExport()
method is called. This immediately shows you the export implements
IDisposable
and will dispose of the export when execution completes in the code block. The object is only initialized when the Value property is called on the ExportLifetime<IMockDbContext>
object ctx. The object is then disposed of when it has finished getting the oldest person from the MockDbContext
, by courtesy of the using block.
public class ProgramManager
{
public IRepository<IPerson> PersonRepo { get; set; }
public ProgramManager(IRepository<IPerson> personRepo)
{
PersonRepo = personRepo;
}
public void SimulateUserAction()
{
var person = PersonRepo.GetByAge(x => x.Age > 21);
System.Console.WriteLine("The oldest person in the table is {0} at the tender age of {1}", person.Name, person.Age);
System.Console.ReadKey();
}
}Colourised in 5ms
Why use ExportFactory<T>?
The benefits of the ExportFactory<T>
come down to the architecture of your application as well as your applications defined requirements. The ExportFactory<T>
for example would be used to minimize the resource intensity of object creation by only calling the object when use of that object is required and also to dispose of that object once it has been used. The Lazy<T>
is a great example of deferred creation of an object, however you do not have finer control when it comes to the objects lifetime. Once the object has been initialized when the Value
property is called on Lazy<T>
, it stays in memory throughout the lifetime of the application. The ExportFactory<T>
differs slightly in that it defers the instantiation of the object, and also provides you with controlling the disposal of the objects instance.
Export Multiple Interfaces
MEF 2 preview 5 now supports the exportation of multiple interfaces on an implemented concrete type.
By way of the ExportInterfaces()
method in the RegistrationBuilder
s Api. There are three method overloads one for exporting all implemented interfaces, the second overload is used to only export interfaces that meet certain criteria and finally the third overload takes a lambda that specifies the ExportBuilder as well as the interface filter.
In the example below we will be using the first and second overload.
Please not the project we are using is called. Learning.MEFII.Console.MultipleInterfaces
Here we have a simple program that shows human
characteristics made up of segregated interfaces by each relating
characteristic. The Person
class implements all these interfaces as they all
relate to a Person
object.
The code is as follows.
public class Person : IHuman, IMammal, IHomosapien
{
public int NoLegs { get; set; }
public HairType HairType { get; set; }
public long IdNumber { get; set; }
public string Name { get; set; }
public Person()
{
NoLegs = 2;
HairType = MultipleInterfaces.HairType.Hair;
IdNumber = 8404295531083;
Name = "Butch";
}
public string BloodType { get; set; }
}
static void Main(string[] args)
{
var p = new Program();
p.RegisterExports();
var humanCharacteristics = p.container.GetExportedValue<IHuman>();
var mammalCharacteristics = p.container.GetExportedValue<IMammal>();
System.Console.WriteLine("Human Characteristics Name: {0} Id Number: {1}",
humanCharacteristics.Name, humanCharacteristics.IdNumber);
System.Console.WriteLine("Mammal Characteristics No of Legs: {0} Type of Hair: {1}",
mammalCharacteristics.NoLegs, mammalCharacteristics.HairType);
System.Console.ReadKey();
}
public void RegisterExports()
{
RegistrationBuilder builder = new RegistrationBuilder();
builder.ForType<Person>()
.ExportInterfaces();
InitializeMef(builder);
}Colourised in 19ms
As you can see all interfaces that implement the person
object are being exported. So when the exported value is requested of the specified
contract type eg interface. Only the properties and methods relating to that
implemented interface are exposed to the client from the Person
object. Please
note that even though I am exporting and retrieving the value of multiple
interfaces. The object is still only created as a singleton by default. By
default the first exported interface to call the concrete type will instantiate
the object. Eg;
Conclusion
This article has gone through the many new exciting features that will most likely be released in the next iteration of MEF which comes out later this year with .NET 4.5. The most notable changes was the removal of attribute driven injection and a far richer api to work with when it came to defining exports and injecting imports. It also provides a lot more flexibility when it comes to the criteria that are set in defining types that are eligible to be registered in the CompositionContainer
. The MEF project has grown from strength to strength; so the future looks bright for MEF and the .NET framework. So watch this space.
Points of Interest
Check this link out.
http://blogs.msdn.com/b/bclteam/archive/2011/12/19/what-s-new-in-mef-2-preview-5-alok-nick.aspx
History
Version 0.1 By Dean Oliver