Testing and Debugging MEF, avoiding misconceptions – Part 3
this is the 3rd post of this series and it will
discuss common misconceptions which may lead unexpected behavior and long
the first misconception occurs when developer are trying to access
imported property at construction time.
MyPlugin instantiation occur when the MEF container composed,
the composition process will create an instance and only then it will try
to satisfy its imports. which mean that at the construction time the imports does not yet satisfied.
the above code will result with NullReferenceException.
What can we do about it?
we can have a few solutions solving this issue:
- we can use ImportingConstructor (but we should use it carefully because
cross import constructor may lead to deadlock and rejection).
this way the logger will be instantiate before the instantiation of MyPlugin.
- we can implement IPartImportsSatisfiedNotification (which is my favorite technique because there is no dead lock risk).
this way we can initialize our component right after all imports has been satisfied.
MEF infrastructure will call OnImportsSatisfied right after it done with the composition process.
None composed instance issue
developers are used to instantiate their own type using the new keyword (var plugin = new MyPlugin()).
doing so wouldn’t satisfy any of the imported properties (because the type doesn’t took part in any composition), because MEF does not aware of the instantiation.
How can we do it right?
- we can introduce the instance to the composition by using ComposePart.
the compose part will satisfy any of the instance imports.
- other solution is getting our instance dynamically from
the container (for example by using GetExportedValue)
- using Silverlight we can initialize our container
by using CompositionHost.Initialize(catalog). and we can add the
following line to the constructor:
CompositionInitializer.SatisfyImports(this), which mean that
each time we are creating new instance it will try to satisfy it’s own imports.
(be aware that you must use CompositionHost.Initialize(catalog) before using
if you want to use the same technique for none Silverlight components,
you can download the code for System.ComponentModel.Composition.Initialization.dll
which hold CompositionHost.Initialize and CompositionInitializer.SatisfyImports
Exporting the wrong type issue
last issue is to avoid exporting or importing the wrong type.
MEF does not goes through the inheritance list,
MEF contract are explicit and doesn’t aware of the inheritance chain.
the following code snippet export the MyLogger (not the ILogger).
it is equivalent to:
while what you may really wanted is:
the following import won’t get the first 2 snippet because of the explicit contract comparison:
MEF instantiation occurs at runtime and sometime it is not
so easy or straight forward for debug.
avoiding common misconceptions may save us long debugging hours.
I strongly recommend the following post which discuss other points of failure: