Зависимости MEF и управление версиями

У меня есть система, которая использует MEF для загрузки деталей. Каждая из этих частей основывается на основной библиотеке. Когда я создаю проект, я добавляю номер версии в DLL файлы следующим образом:

  • part1-1.0.0.0.dll
  • part2-1.0.0.0.dll

Кроме того, есть приложение, которое выполняет композицию MEF. Он также использует основную библиотеку. Я обнаружил, что я могу просто развернуть DLL "part", и композиция прекрасно работает, потому что приложение уже загрузило основную библиотеку, на которую полагаются части. Поэтому моя файловая система выглядит примерно так:

  • /parts/part1-v1.dll
  • /parts/part2-v1.dll
  • композитор-v1.exe
  • ядро-v1.exe

У меня возникла проблема с управлением версиями ядра и частей. Предположим, что я делаю обновление для ядра и одной из частей. Затем я развертываю изменения. Итак, теперь моя файловая система может выглядеть примерно так:

  • /parts/part1-v1.dll
  • /parts/part1-v2.dll
  • /parts/part2-v1.dll
  • композитор-v1.exe
  • ядро-v1.dll
  • ядро-v2.dll

Как я могу убедиться, что part1-v1.dll использует core-v1.dll, а part1-v2.dll использует core-v2.dll? Мне нужны все версии загружаемых частей и использование соответствующей версии ядра.

Классы классов выглядят примерно так:

[Export(typeof(IPart))]
public class Part1
{
    public string GetSomethingFromCore()
    {
        return Core.GetSomethingFromCore();
    }
}

[Export(typeof(IPart))]
public class Part2
{
    public string GetSomethingFromCore()
    {
        return Core.GetSomethingFromCore();
    }
}

Ответ 1

Не сильное именование заботится о вашей проблеме? Если сборка создается против сильной именованной зависимости, то вы знаете, что она будет принимать только ту же самую зависимость до последнего байта.

В качестве альтернативы, если сильное именование слишком ограничительно, вы можете поместить номера версий в имена типов. Например:

[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;
    }
}

Ответ 2

Вам нужно предоставить свою основную сборку всем вашим частям сильные имена, тогда они потребуют точного соответствия при загрузке ссылочных ассемблеров. Это также означает, что вам нужно будет развернуть несколько копий вашей основной сборки. То есть вместо

  • /parts/part1-v1.dll
  • /parts/part1-v2.dll
  • /parts/part2-v1.dll
  • композитор-v1.exe
  • core-v1.dll
  • ядро-v2.dll

У вас будет:

  • /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
  • композитор-v1.exe
  • core-v1.dll
  • ядро-v2.dll

То, как я это делал в прошлом, - это просто сохранить каждую часть в отдельной папке вместе со всеми необходимыми зависимостями. Даже если они (в настоящее время) такие же версии, как в приложении. Так что, когда приложение переходит на ядро-v2, все части, которые полагаются на core-v1, все равно будут иметь его.