At work, we have several related products and we want to be able to upgrade one of them without upgrading the others. Part of the solution has been to use a plugin architecture based on the Managed Extensibility Framework (MEF). Something like this:
[Import]
IMyInterface _myPlugin = null;
public void DoImport()
{
using (var catalog = new DirectoryCatalog(Properties.Settings.Default.PluginFolder))
{
using (var container = new CompositionContainer(catalog))
{
container.SatisfyImportsOnce(this);
}
}
}
The Problem
I had a type -- call it MyPluginA, that implemented the imported interface, IMyInterface. At one point, I was getting this mysterious error:
System.ComponentModel.Composition.CompositionException:
The composition produced a single composition error. The root cause
is provided below. Review the CompositionException.Errors property
for more detailed information.
1) The export 'MyFirstPlugin.MyPluginA (ContractName="MyInterfaces.IMyInterface")'
is not assignable to type 'MyInterfaces.IMyInterface'.
Etc., etc.
What in the world??? MyPluginA inherits from IMyInterface! How can it not be assignable to it?
The Solution
It turned out that the plugin had been linked with version 1.0 of the interface's assembly, while the component that was trying to import it was linked with version 2.0. It didn't matter that the interface had not changed at all going from version 1.0 to version 2.0. As far as MEF was concerned, they represented two different types.
I have found that it's good practice to isolate interfaces, data contracts and other types that form the hinge-points between components, in their own assembly. What I learned is that it's a bad idea to let the version of that assembly change. To be more precise, let the AssemblyFileVersion change, but not the AssemblyVersion. The AssemblyFileVersion is just human-readable documentation, and is ignored by the .NET Framework. You can use it to determine which version you're "really" dealing with.
[assembly: AssemblyVersion("1.0.0.0")] // This should rarely change in interface assemblies
[assembly: AssemblyFileVersion("1.0.0.0")] // This can change whenever you want.
In future posts, I'm going to develop some Laws of Composibility. For now, I thought I'd pass on the solution I found to this initially puzzling error.