October 2010 - Posts
Exporting non Exportable types
this post extend Glenn Block's post about
"Poco, Mef, and custom type systems. Are you ready to take the red pill?"
the post is adding a compile time attribute export model, Directory catalog
and migrate Glenn code to VS 2010.
It is very recommended to read Glenn Block's post before reading
this one.
the code sample for this post can be download from here.
Summarizing Glenn's post
in general Glenn show how to add attributes (like Export) to 3rd party type
which doesn't support it (it is cool technique which doesn't related directly to MEF).
Glenn show how to write catalog which can be aware of types extension.
What was added?
I took Glenn's source, fix it to run against the CLR 4.0,
then I added a directory catalog which aware of the
type extension and I also add a nice clean way of exposing the type
by using assembly level attribute.
the directory catalog is very straight forward so I wont cover it in the post
(you can download the source and see the implementation).
the following code show how to use the assembly level attribute:
Code Snippet
- [assembly: ComposablePartRegistry(typeof(MyNoneExportedType), typeof(IMyNoneExportedType))]
as you can see, all you have to do is to declare the exported type followed by the exported contract.
the attribute snippet:
Code Snippet
- [AttributeUsage (AttributeTargets.Assembly)]
- public class ComposablePartRegistryAttribute : Attribute
- {
- public ComposablePartRegistryAttribute(
- Type implementation, Type contract,
- CreationPolicy policy = CreationPolicy.Any)
- {
- Type t = typeof (ComposablePartType<,>);
- t = t.MakeGenericType(new[] {implementation, contract});
- Type = Activator.CreateInstance(t, policy) as TypeDelegator;
- }
-
- public TypeDelegator Type { get; private set; }
- }
line 8-10: creating ComposablePartType type which later be used by the catalog.
Summary
this was small extension to Glenn's concept which can be very useful
in cases where you want to embrace 3rs party component into your MEF model.
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
debugging nights.
Initialization issues
the first misconception occurs when developer are trying to access
imported property at construction time.
NullReferenceException
- [Export]
- public class MyPlugin
- {
- public MyPlugin()
- { // the logger import doesn't satisfied yet
- // the next line will result with NullReferenceException
- Logger.Write("MyPlugin initialized");
- }
-
- [Import]
- public ILogger Logger { get; set; }
- }
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).
ImportingConstructor
- [Export]
- public class MyPlugin
- {
- // cross import constructor can lead to deadlock an rejection
- [ImportingConstructor]
- public MyPlugin(ILogger logger)
- {
- logger.Write("MyPlugin initialized");
- }
- }
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.
IPartImportsSatisfiedNotificat
- [Export]
- public class MyPlugin: IPartImportsSatisfiedNotification
- {
- public void OnImportsSatisfied()
- {
- // happens just after the imports satisfaction
- Logger.Write("MyPlugin initialized");
- }
-
- [Import]
- public ILogger Logger { get; set; }
- }
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.
ComposeParts
- [TestMethod]
- public void GetInstanceFromContainerTest()
- {
- var catalog = new AssemblyCatalog(typeof(ILogger).Assembly);
- var container = new CompositionContainer(catalog);
-
- var plugin = new MyPlugin(); ;
- container.ComposeParts(plugin);
-
- Assert.IsNotNull(plugin.Logger);
- }
-
- public interface ILogger
- {
- void Write(string content);
- }
-
- [Export(typeof(ILogger))]
- public class MyLogger:ILogger
- {
- public void Write(string content)
- {
- Debug.WriteLine(content);
- }
- }
-
- [Export]
- public class MyPlugin
- {
- [Import]
- public ILogger Logger { get; set; }
- }
- other solution is getting our instance dynamically from
the container (for example by using GetExportedValue)
GetExportedValue
- [TestMethod]
- public void GetInstanceFromContainerTest()
- {
- var catalog = new AssemblyCatalog(typeof(ILogger).Assembly);
- var container = new CompositionContainer(catalog);
- container.Compose(new CompositionBatch());
-
- MyPlugin plugin = container.GetExportedValue<MyPlugin>();
-
- Assert.IsNotNull(plugin);
- Assert.IsNotNull(plugin.Logger);
- }
-
- public interface ILogger
- {
- void Write(string content);
- }
-
- [Export(typeof(ILogger))]
- public class MyLogger:ILogger
- {
- public void Write(string content)
- {
- Debug.WriteLine(content);
- }
- }
-
- [Export]
- public class MyPlugin
- {
- [Import]
- public ILogger Logger { get; set; }
- }
- 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
CompositionInitializer.SatisfyImports(this))
SatisfyImports
- public class MyPlugin
- {
- public MyPlugin()
- {
- CompositionInitializer.SatisfyImports(this);
- }
-
- [Import]
- public ILogger Logger { get; set; }
- }
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
from here.
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).
Code Snippet
- [Export]
- public class MyLogger:ILogger {
- ...
- }
it is equivalent to:
Code Snippet
- [Export(typeof(MyLogger))]
- public class MyLogger:ILogger {
- ...
- }
while what you may really wanted is:
Code Snippet
- [Export(typeof(ILogger))]
- public class MyLogger:ILogger {
- ...
- }
the following import won't get the first 2 snippet because of the explicit contract comparison:
Code Snippet
- [Import]
- public ILogger Logger { get; set; }
Summary
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.
Read more
I strongly recommend the following post which discuss other points of failure:
The hidden assumption of EF 4 self-tracking entity

recently I was diving into the Entity Framework self-tracking entity T4 and its generated code.
doing so I was finding some interesting assumptions made about the entity behaviors.
this post will illuminate some of those assumptions.
Background
EF self tracking entity is one of the major enhancement of EF 4.0,
it is a disconnected model (similar to the old DataSet) which enable tracking
the entity state (Added, Modified, Deleted and Unchanged) while the entity
is detached from the EF ObjectContext.
the code snippet of this post will refer the following very simple edmx:
Assumptions
1st assumption
by default the tracking is disable (ChangeTrackingEnabled = false).
2nd assumption
trying to change the entity state while the tracking is disable
Code Snippet
- var p = new Person();
- p.ChangeTracker.State = ObjectState.Unchanged;
will have no affect on the entity state (the state will remain Added which is the default
state for new entities).
the following snippet shows the code of the State property:
T4 generated code
- public ObjectState State
- {
- get { return _objectState; }
- set
- {
- if (_isDeserializing || _changeTrackingEnabled)
- {
- OnObjectStateChanging(value);
- _objectState = value;
- }
- }
- }
3rd assumption
the entity enable the tracking after deserialization.
T4 generated code
- [OnDeserialized]
- public void OnDeserializedMethod(StreamingContext context)
- {
- IsDeserializing = false;
- ChangeTracker.ChangeTrackingEnabled = true;
- }
4th assumption
MarkAsAdded, MarkAsModified, MarkAsDeleted and MarkAsUnchanged all enable the trucking.
T4 generated code
- public static T MarkAsAdded<T>(this T trackingItem) where T : IObjectWithChangeTracker
- {
- trackingItem.ChangeTracker.ChangeTrackingEnabled = true;
- trackingItem.ChangeTracker.State = ObjectState.Added;
- return trackingItem;
- }
5th assumption
State = ObjectState.Unchanged, MarkAsUnchanged and AcceptChanges
has different behaviors:
in general State property: is only changing when tracking is enabled,
MarckAsUnchanged: enable the tracking and
AcceptChanges: clear the original values, enable the tracking and
reset the relationship tracking (added and removed related entities).
State: T4 generated code
- public ObjectState State
- {
- get { return _objectState; }
- set
- {
- if (_isDeserializing || _changeTrackingEnabled)
- {
- OnObjectStateChanging(value);
- _objectState = value;
- }
- }
- }
MarkAsUnchanged: T4
- public static T MarkAsUnchanged<T>(this T trackingItem) where T : IObjectWithChangeTracker
- {
- trackingItem.ChangeTracker.ChangeTrackingEnabled = true;
- trackingItem.ChangeTracker.State = ObjectState.Unchanged;
- return trackingItem;
- }
AcceptChang: T4 generated code
- public void AcceptChanges()
- {
- OnObjectStateChanging(ObjectState.Unchanged);
- OriginalValues.Clear();
- ObjectsAddedToCollectionProperties.Clear();
- ObjectsRemovedFromCollectionProperties.Clear();
- ChangeTrackingEnabled = true;
- _objectState = ObjectState.Unchanged;
- }
Summary
the self tracking entity is a fairly young concept in the EF world
and we can expect that it will keep changing.
as I was reading in one of the Harry Potter's book
"do not trust anything you cannot understand", so be aware of that
assumption and use it well.
Testing and Debugging MEF, Tips - Part 2
this is the second post of a series that will offer some tips
about testing and debugging your MEF-able component and application.
in this post we will focus about debugging the most common, and most confusing,
MEF failure.
Assembly Loading Failure
the most common MEF runtime failure occurs because of missing assembly
which contain the MEF parts (Import, Export) or
the parts dependencies (like 3rd party components).
under the hood MEF is using reflection, which mean that MEF loading
behavior is similar to the reflection dynamic loading.
Tracing Loading Failure?
I will suggest 2 option for tracing the failure:
1. we can register to assembly resolve event (AppDomain.CurrentDomain.AssemblyResolve)
Code Snippet
- AppDomain.CurrentDomain.AssemblyResolve += OnAssemblyResolveHandler;
- static Assembly OnAssemblyResolveHandler(object sender, ResolveEventArgs args)
- {
- Logger.WriteLine("Assembly Resolve: " + args.Name);
-
- return args.RequestingAssembly;
- }
the problem with that approach is that we may get some smoke events which
actually succeed (because of the .NET probing).
2. catching ReflectionTypeLoadException exception
Code Snippet
- try
- {
- container.ComposeParts(p);
- }
- catch (ReflectionTypeLoadException ex)
- {
- foreach (Exception exc in ex.LoaderExceptions)
- {
- Logger.WriteLine(exc.Message);
- }
- }
we can wrap the composition using try catch scope.
and catch ReflectionTypeLoadException. this will
give us pretty good idea what's got wrong.
Summary
my suggestion is whenever possible, wrapping any composition and catch the ReflectionTypeLoadException, in other cases we can use the first technique.
Credits
Ohad Schneider should have credit for part of the code in this post.