Использование разных версий одной и той же сборки в одной папке

У меня следующая ситуация.

Проект A

 - Uses Castle Windsor v2.2
 - Uses Project B via WindsorContainer

Проект B

 - Uses NHibernate
 - Uses Castle Windsor v2.1

В папке bin проекта A у меня есть dll Castle.DynamicProxy2.dll v2.2 и NHibernate dll. Теперь проблема в том, что NHibernate зависит от Castle.DynamicProxy2.dll v2.1, которого нет. Как разрешить эту ситуацию.

Ответ 1

Для решения проблемы я использовал следующую конфигурацию.

<configuration>
    <runtime>
        <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
            <dependentAssembly>
                <assemblyIdentity name="Castle.DynamicProxy2" publicKeyToken="407dd0808d44fbdc" />
                <codeBase version="2.1.0.0" href="v2.1\Castle.DynamicProxy2.dll" />
                <codeBase version="2.2.0.0" href="v2.2\Castle.DynamicProxy2.dll" />
            </dependentAssembly>
            <dependentAssembly>
                <assemblyIdentity name="Castle.Core" publicKeyToken="407dd0808d44fbdc" />
                <codeBase version="1.1.0.0" href="v2.1\Castle.Core.dll" />
                <codeBase version="1.2.0.0" href="v2.2\Castle.Core.dll" />
            </dependentAssembly>
        </assemblyBinding>
    </runtime>
</configuration>

Ответ 2

Одним из решений (или обходным путем) было бы установить обе версии в Глобальном кэше сборки (GAC) на компьютере (-ах), на котором должно выполняться ваше программное обеспечение, и ссылаться на сборки, используя их сильные имена. Это предполагает, что сборки действительно имеют прочные имена.

Установка в GAC будет больно, если у вас будет несколько разработчиков или если вы планируете развернуть свое решение на многих компьютерах (например, в качестве приложения для конечного пользователя). В этом случае я полагаю (но, возможно, ошибаюсь), что ваш единственный вариант - объединить одну из двух версий в сборку, требующую этой версии. В вашем конкретном случае вам нужно Castle.DynamicProxy2.dll v2.1 объединиться в NHibernate.dll.

Вы можете использовать инструмент ILMerge для объединения сборок. Команда, которую вам нужно запустить, выглядит примерно так (непроверенная):

ILMerge /t:library /internalize /out:Deploy/NHibernate.dll
    NHibernate.dll Castle.DynamicProxy2.dll

Коммутатор /internalize сообщает ILMerge отмечать все типы из второй сборки (замок в этом случае) internal в сборке вывода. Без этого вы можете получить ошибки компиляции при попытке скомпилировать проект, ссылающийся на ваш новый NHibernate.dll и на полку версии Castle.DynamicProxy2.dll v2.2, так как они будут содержать классы с одинаковыми именами.

Ответ 3

Одна вещь очень, очень, очень важная, что можно пропустить, если он не уделяет достаточного внимания.

Сборка, которую вы пишете в теге версии codeBase, должна быть сильной.

Из следующей ссылки: http://msdn.microsoft.com/en-us/library/efs781xb.aspx

Для сборок без сильного имени версия игнорируется, а загрузчик использует первое появление <codebase> внутри <dependentAssembly> . Если в приложении есть запись файл конфигурации, который перенаправляет привязку к другой сборке, перенаправление будет иметь приоритет, даже если версия сборки не будет соответствие запросу привязки.