Recently, I dug deep into MEF because I was involved in a project where there was a decision to upgrade the WPF client to PRISM 4 and advance to using MEF alone instead of Unity.
While many argue that MEF isn’t yet a full DI framework, it still provides an easy way to enable application extensibility in your projects.
One of the tasks that I had while upgrading the client to PRISM 4, is to keep supporting type registration in runtime, something in the sort of the following -
Code Snippet
- public interface IFoo
- {
- }
-
- [Export(typeof(IFoo))]
- public class Foo : IFoo
- {
- }
-
- catalog.Register<Bar>();
The built-in TypeCatalog that comes with MEF requires you to specify the types in the constructor and there is no support for registrations in runtime for the same catalog.
In order to support this feature, I could simply add a new TypeCatalog for every registration request in runtime with the desired type, but that seemed to be kind of wasteful.
MEF does support catalog changes in runtime, you need to implement ‘INotifyComposablePartCatalogChanged’.
The solution
I implemented a type catalog that supports registrations in runtime, here is the core implementation -
Code Snippet
- public void Register(IEnumerable<Type> types)
- {
- if (types != null)
- {
- List<ComposablePartDefinition> addedParts = new List<ComposablePartDefinition>();
-
- foreach (Type type in types)
- {
- ComposablePartDefinition part = AttributedModelServices.CreatePartDefinition(type, null);
-
- addedParts.Add(part);
- }
-
- using (var atomicComposition = new AtomicComposition())
- {
- OnChanging(new ComposablePartCatalogChangeEventArgs(addedParts, EmptyPartDefinitions, atomicComposition));
-
- _lock.EnterWriteLock();
- try
- {
- foreach (var addedPart in addedParts)
- {
- _parts.Add(addedPart);
- }
- }
- finally
- {
- _lock.ExitWriteLock();
- }
-
- atomicComposition.Complete();
- }
-
- OnChanged(new ComposablePartCatalogChangeEventArgs(addedParts, EmptyPartDefinitions, null));
- }
- }
If I need to register known types in runtime, I can just do the following -
Code Snippet
- RuntimeTypeCatalog catalog = new RuntimeTypeCatalog();
-
- CompositionContainer container = new CompositionContainer(catalog);
-
- catalog.Register<Bar>();
- catalog.Register<Foo>();
Feel free to download the full source code and see it in action.