The Common Service Locator project has a bunch of adapters. One of them is the one for Managed Extensibility Framework (MEF). I’ve updated the adapter to run on MEF Preview 6 and uploaded the result to the Codeplex site for the CSL.
Common Service Locator MEF adapter
Note: I’ve been nagging on Glenn Block to update the adaptor project that hooks up MEF to the Common Service Locator. Not so much nagging on him to do it, the man has enough to do, but rather nagging on him to add med as a developer on the CSL project so that I could do the update for him. Reason for me to bother doing this is that it is a nice blog post for med to put out there and an opportunity to drum out the message that the way to go is to use services and contracts based on the principles of Inversion of Control (IoC) and Dependency Injection (DI)! Glenn finally let up and added me as one of the devs on the project. Cool to be on the same list as some truly brilliant and remarkable people – who knows genius might rub off:
(Hi again you guys – the bad penny is back ;~))
What is the CSL?
The best place to read up on this project is here: Common Service Locator Project Rationale. The project sprung from Jeremy D. Millers classic post: It's time for IoC Container Detente and taken forward by Oren Eini (Ayende) with his work behind the scenes: The Common Service Locator library.
Should I use this library for my applications?
Generally no, but it is very flexible design if you do decide to use it! ;~) See below for a scenario where it can be motivated and successfully used. “Once you've decided on a container that suits your project, there's not a whole lot of benefit from writing your whole application in a way that can switch containers. For libraries that must fit into other ecosystems and play nicely with other libraries, it's an important feature[…]” Consuming the Interface
Is MEF a DI Container?
What kind of question is this? Well. It’s like this: Managed Extensibility Framework – a piece of .NET Framework that will ship with .NET 4.0 is a piece of the .NET framework that aims to solve the software extensibility in a unifying way in the .NET Framework. “It is a systemic measure of the ability to extend a system and the level of effort required to implement the extension.” (wiki)
As such MEF has to use some sort of technique to enable extensibility in any code base. Turns out that DI and IoC is a very good way to address this challenge. Thus MEF uses those principles to do the work of enabling extensibility. And thus it in many ways works as a DI Container.
Consider: Using a DI Container built for this purpose if it is a DI container you are looking for.
But go ahead and use MEF if you like – it is a very good piece of framework that works for a lot of scenarios OOTB.
Let me comment on the changes to MEF that are now running in the new CSL MEF adaptor:
Attributed Model Services: MEF is now moving toward release and the old CompositionServices class has been renamed AttributedModelServices which is a more apt name. “Contains helper methods for using the attributed programming model with composition.” For those of you who know MEF allows the whole model of how extensions are discovered to be exchanged with any other custom model you like. OOTB MEF ships with an attributed model that bases discovery on attributes in the code: ExportAttribute and ImportAttribute.
Export<T> is dead. Long live Lazy<T>: Just to be able to use a class named “Lazy”! ;~) The Lazy<T> class “Provides support for several common patterns of lazy initialization, including the ability to initialize value types and to use null values.” The old Export<T> class was a lazy-instantiate-wrapper that enabled you to look at all potential matches for an extension and select one based on some metadata.
.GetExportedObject() is now .Value: And .GetExportedObjects is now .GetExportedValues. When you ask a Lazy<T> for it’s instance you do so by accessing the property .Value. Export<T> had a method for the same purpose. Generally speaking I try to avoid complex logic in property getters and setters. Some times however it is a valid approach and this is such a case. The .Value in a Lazy class naturally means the instantiation and returning of a new instance (or shared) of the wrapped type. It is logical and I don’t think developers will be surprised in this case. However in other cases having a property do lots of logic or even a remote call is in my book not recommended. Make sure it is clear that your getter is executing all this logic to be able to return your expected value. When you ask the provider for exported values it is still a method and not a list of values in a property. See the difference? Lazy<T>.Value vs. provider.GetExportedValues<T>().
Note: There is also the class Lazy<T, TMetadata> which can be used (but it is not used in the CSL) which helps us to add a strongly typed metadata contract to all extensions when they are exported through MEF. This would help us when we import many extension to add some descriptive metadata used either by the program or the human using the program to be able to select between many potential candidates for extensions.
Usage scenario for CSL:
Finally – have I used this? Is there a value in using it? Yes I have and yes there is value given that your scenario really can benefit from using it. The answer to the second question is “it depends”. ;~)
I have been involved in a project where we have been building test support for many different applications produced at this company X. The company has many developers, many projects and many ways of doing things. Naturally internal code conventions, framework and external application usage will vary in a large organization.
We were building test support for everyone and were faced with the potential of other departments picking up our code to refine our general test support for their applications.
What if we decided to use Unity and they were using Castle Windsor or Spring.NET or StructureMap or Autofac, or…?
There was a real possibility that our testing framework had to win over the other departments and if a potentially hostile (or at least a bit unfriendly) developer at some other department picked up our code to find we were using some other piece of code than what he was used to there would be a risk that he would refuse to use our code.
Given this scenario we opted for using
- The CLS to enable any choice of DI Container.
- MEF a core .NET Framework building block that is aimed to make life very much easier for developers faced with extensibility. In fact we chose to view all implementations of the test support as extensions in order to support an open set of extensions and to make it very much easier for the developers at the different departments to consume and adopt our work.
Consider: Using CSL and/or MEF if this or a similar scenario is your scenario.
HTH - Cheers,
M.
posted @ Monday, August 10, 2009 11:38 AM