Divagations presented here are partially based on a great post titled Hosting MEF Extensions in an IoC Container by Nicholas Blumhardt, and I recommend you take a look at it before further reading this post :).
Problem
People around are sometimes/often confused about the role MEF plays in the world of the Dependency Injection – should MEF be treated as an Injection of Control solution, and thus should supersede it, or it is something else and should be used differently? Well, this is a little bit tricky question, but in what I understand, MEF is all about composition and robust components loading, thus is best suited for providing well-known extension (plug-ins) to the application, whereas IoC serves more as a backbone of an application, which is primary responsible for making all application’s internal modules work together. To sum up, MEF and Unity are very flexible and in many cases may be used interchangeably, but a general idea is that:
- if you want to provide a plug-ins infrastructure so that 3rd parties were able to provide extensions for the app, use MEF (or Managed Add-in Framework + MEF if you want robust plug-in isolation :)),
- if you want to structure your application’s architecture, use modules that are decoupled but with the ability to communicate, etc., use Unity or any existing IoC.
The first solution is pretty easy – simply use both frameworks independently of each other.
The definite plus of this approach is its ease of putting it into action in the application. But it has some drawbacks, mainly that MEF and Unity components can’t make use of each other. In other words, MEF component cannot contain any dependencies on Unity components that can be automatically satisfied via dependency injection. The same holds true for the Unity components, they simply cannot have dependencies on MEF components (note that by MEF component I mean component initially instantiated by MEF, and by Unity component I mean a component initially created by Unity container). Another drawback is that unity does know nothing about MEF, and vice versa. And why is that important ? Consider the following sample showing a dummy Presentation Model in presenter first approach (a typical scenario):
public class MyViewPresentationModelNote that in the constructor, I have both Unity service and MEF component, and because the MyViewPresentationModel class is instantiated via Unity and Unity knows nothing about IMefComponent1, this won’t work. But it should! Argh...
{
public MyViewPresentationModel(IMyView view, IUnityService1 service1,
IMefComponent1 mefComponent1)
{
}
}
Although this solution is fairly simple to implement, it has several drawbacks that makes using it painful. So let’s go to the second :)
Solution 2
This solution uses a middle component, Unity + MEF Integration Layer (implemented as Unity.Integration.Mef.dll), which allows full interoperability between Unity and MEF, as you can see from the following figure.
As you can see, Unity is the backbone component, that uses the integration layer to communicate with MEF. In this solution, Unity components may have dependencies on MEF components, and vice versa. Of course, all dependencies will by injected automatically! So the following code will work (ICoreService is a Unity service whereas IMefService is instantiated by MEF):
What's even more important, with this approach, it's possible to mix components in the constructors, so the following both classes will work as well. Please note, that if you have a MEF component exported by name, you can reference it using the Unity's DependencyAttribute, and if you have a Unity component registered using a name, you can reference it in a MEF component using MEF's ImportAttribute ! :)
public class CoreService2 : ICoreService
{
public CoreService2()
{
}
[Import("MefService3")]
private IMefService m_MefService3;
public void Foo()
{
}
}
public class CoreComponent : (...)Using the Unity + MEF Integration Layer is very simple, just reference Unity.Integration.Mef.dll in your project and you're almost done! Here's a sample:
{
private readonly IMefService m_MefService3;
private readonly ICoreService m_CoreService;
// Interesting thing happens here: Unity injects components created
// by both MEF and Unity
public CoreComponent(
[Dependency("MefService3")] IMefService mefService3,
ICoreService coreService)
{
m_MefService3 = mefService3;
m_CoreService = coreService;
}
[Import(AllowDefault = true)]
private IEnumerable<imefservice> m_MefServices;
public void FooBar()
{
}
}
[Export(typeof(IMefService))]
[PartCreationPolicy(CreationPolicy.Shared)]
public class MefService2 : IMefService
{
private readonly IUnityContainer m_UnityContainer;
private readonly ICoreService m_CoreService;
// Interesting thing happens here: MEF injects components created
// by both MEF and Unity
[ImportingConstructor]
public MefService2(IUnityContainer unityContainer,
[Import("CoreService2")] ICoreService coreService)
{
m_UnityContainer = unityContainer;
m_CoreService = coreService;
}
public void Bar()
{
}
}
// Create the Unity container and self-register
var unity = new UnityContainer();
unity.RegisterInstance<IUnityContainer>(unity);
// Register MEF catalogs in Unity
unity.RegisterCatalog(new AssemblyCatalog(Assembly.GetEntryAssembly()));
unity.RegisterCatalog(new DirectoryCatalog("."));
// Register unity components
unity.RegisterType<CoreComponent>();
unity.RegisterType<ICoreService, CoreService1>(new ContainerControlledLifetimeManager(), true);
unity.RegisterType<ICoreService, CoreService2>("CoreService2", new ContainerControlledLifetimeManager(), true);
The public interface is defined using extension methods on the IUnityContainer interface. There are two thing you have to do. Firstly, register all the MEF's catalogs in the Unity. Secondly, register the types in the Unity as you normally do. Note, however, that in order to make a type registered in the Unity container available to MEF, you must register it with an overloaded Register(Type|Instance) method that accepts a boolean as the last parameter. If it is true, registered type/instance will be available to MEF.
Sometimes you will want to suppress MEF injections into Unity created instances. Why? Because it costs you a CPU cycles (believe me, lots of them!). This is where PartNotComposableAttribute attribute comes in. Just mark a class with it, and when an instance from the Unity is returned, no MEF's imports will be satisfied, conserving CPU time. This is particularly useful for presenters.
Limitations
For now, MEF components can have Unity dependencies resolved only via constructor injection, so method injection on MEF components currently won't work.
Implementation details
The implementation is rather straightforward. It uses two Unity extensions and one custom MEF ExportProvider. As stated before, public interface is delivered as a set of extension methods on the IUnityContainer interface. I've also considered deriving directly from UnityContainer class, but the former approach (the one I've chosen) appears better suited for me. What do You think ? You can leave a comment on that :)
Conclusion
The idea of bringing the power of both frameworks is very tempting. And provided solution, although definitely not the only one, seems like a good one. The code + tests (NUnit 2.5) + demo app is available on my code gallery. Hope you like it!
Update
I've reimplemented most of the layer from the ground up, now it's a part of the MEFContrib project. Please see my post about it here.
12 comments:
Nice job Piotr! It's great to see this finally getting out there. I enjoyed chatting with about you about this in Poland, even more exciting to see it go live!
Thank you for sharing this article.
Do you know if this approach will still work with the latest MEF release (Preview 8)?
Cheers,
Eric
Hello
Thanks for this great Post.
But where do you find "Unity.Integration.Mef.dll" ?
I try to make an silverligth application using Prim & MEF. I've see the MEF contrib projet but it still not work with Silverlight.
Could you help me ?
Thanks
@Eric
Yes, this approach still works with MEF Beta 2 (Preview 8). Actually, unless done by MEF / P&P teams, this approach should be valid for the RTM as well :) (IMHO)
@Manager
I'm going to take a look at MEF + SL3 + MEF Contrib in the near future, so stay tuned ;)
Thanks for your help Piotr
Hello Piotr
nice job. I would like to know if there are any drawbacks to not use MEF Composition container ?
In fact in my project I would like to manage internal dependencies with standard IoC container and to be open using MEF for other develppers.
Using Unity with integration layer to MEF seems the most convenient solution. What's you thoughts?
I'm getting a timeout error when I attempt to connect to the code gallery link. Is your example project available elsewhere?
I have been trying to get your code to work but keep failing. Is there an example project somewhere. Please .
aha Found example code in the tests on the update on github
This website is really a stroll-by means of for the entire information you wished about this and didn’t know who to ask. Glimpse here, and also you’ll undoubtedly uncover it. best online casinos
Post a Comment