I have a system that uses MEF to load parts. Each of these parts rely on a core library. When I build the project, I add a version number to the .dll files like this:
- part1-1.0.0.0.dll
- part2-1.0.0.0.dll
Also, there is an application that performs MEF composition. It also uses the core library. I've found that I can just deploy the "part" dlls, and composition works fine because the application has already loaded the core library that the parts rely on. So my file system looks something like this:
- /parts/part1-v1.dll
- /parts/part2-v1.dll
- composer-v1.exe
- core-v1.exe
The trouble I'm having is how to handle versioning of the core and parts. Suppose I make an update to the core, and one of the parts. Then, I deploy the changes. So now my file system might look something like:
- /parts/part1-v1.dll
- /parts/part1-v2.dll
- /parts/part2-v1.dll
- composer-v1.exe
- core-v1.dll
- core-v2.dll
How can I make sure that part1-v1.dll uses core-v1.dll, and part1-v2.dll uses core-v2.dll? I need all versions of the parts to be loaded and using the appropriate version of the core.
The part classes look something like this:
[Export(typeof(IPart))]
public class Part1
{
public string GetSomethingFromCore()
{
return Core.GetSomethingFromCore();
}
}
[Export(typeof(IPart))]
public class Part2
{
public string GetSomethingFromCore()
{
return Core.GetSomethingFromCore();
}
}
Doesn't strong naming take care of your issue? If an assembly is build against a strong named dependency, then you know that it will only accept the exact same dependency down to the last byte.
Alternatively, if strong naming is too restrictive, you could put version numbers in the type names. For example:
[Export(typeof(IPart))]
public class Part1v1
{
private readonly ICorev1 core;
[ImportingConstructor]
public Part1v1(ICorev1 core)
{
this.core = core;
}
}
[Export(typeof(IPart))]
public class Part1v2
{
private readonly ICorev2 core;
[ImportingConstructor]
public Part1v2(ICorev2 core)
{
this.core = core;
}
}
You need to give your core assembly all of your parts strong names, then they will require an exact match when loading the referenced assemblies. This also means you will need to deploy multiple copies of your core assembly. I.e. instead of
- /parts/part1-v1.dll
- /parts/part1-v2.dll
- /parts/part2-v1.dll
- composer-v1.exe
- core-v1.dll
- core-v2.dll
You will have:
- /parts/1-1/part1-v1.dll
- /parts/1-1/core-v1.dll
- /parts/1-2/part1-v2.dll
- /parts/1-2/core-v2.dll
- /parts/2-1/part2-v1.dll
- /parts/2-1/core-v1.dll
- composer-v1.exe
- core-v1.dll
- core-v2.dll
The way I've done that in the past, is just to store each part in a separate folder along with all of the dependencies it needs. Even if they are (currently) the same version as in the application. So that when you're application moves on to core-v2, all the parts that relied on core-v1 will still have it.