Как построить / развернуть проект, который требует нескольких версий одной и той же сборки? - PullRequest
8 голосов
/ 05 сентября 2010

Я работаю над проектом, использующим конфликт.dll версии 6.2, но в проекте также используется helper.dll, использующий конфликт.dll версии 5.8.

Я мог бы установить 6.2 и 5.8 в GAC, но я бы хотел, чтобы этот проект xcopy был развернут. Я полагаю, что .net будет искать сборки в каталоге bin приложения следующим образом: \ bin \ конфликт.dll (6.2) \ bin \ 5.8 \ конфликт.dll (5,8)

Но на этом этапе, как мне добавить в проект ссылку на обе версии конфликта.dll, а затем как убедиться, что старый файл конфликта.dll разворачивается в \ bin \ 5.8? Создать действие для сборки или есть другой способ?

Спасибо

Ответы [ 3 ]

14 голосов
/ 07 июня 2012

После многих часов поиска и ругательства я нашел решение, которое работает, и его легко и надежно реализовать.

Проблема , как и во всех других ответах, заключается в том, что должны выполняться все следующие условия:

  1. Обе версии DLL должны иметь одинаковые имена, в противном случае среда выполнения будет жаловаться, что имя не соответствует манифесту.
  2. Среда выполнения должна быть в состоянии найти обе сборки в пути поиска.
  3. Перенаправление версии невозможно из-за критических изменений.
  4. AppDomain.ResolveAssembly никогда не вызывается в этом примере, поскольку сборка уже была загружена один раз.

Решение состоит из следующих шагов:

  1. Создайте каталог в каталоге решений, например lib\, с помощью эта иерархия:

    Lib \ Conflict \ v1 \ Conflict.dll
    Lib \ Conflict \ v2 \ Conflict.dll

  2. Добавьте следующее к вашему app/web.config:

<runtime>
  <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
    <dependentAssembly>
      <assemblyIdentity name="Conflict" publicKeyToken="111111111111" />
      <codeBase version="1.0.0.0" href="bin\Conflict\v1\Conflict.dll" />
      <codeBase version="2.0.0.0" href="bin\Conflict\v2\Conflict.dll" />
    </dependentAssembly>
  </assemblyBinding>
</runtime>
  1. Добавить событие после сборки с xcopy:

    xcopy $ (SolutionDir) \ lib $ (TargetDir) / Y / S

  2. Создайте один раз, чтобы скопировать файлы. Нажмите «Проект -> Показать все файлы». Щелкните правой кнопкой мыши на bin\Conflict и выполните Include in Project (избавляет вас от выполнения этого в коде). Это необходимо для развертывания файлов при упаковке веб-приложения.

Готово!

3 голосов
/ 06 сентября 2010

Я полагаю, что .net будет искать сборки в бункере приложения каталог вроде так: \ bin \ конфликт.dll (6.2) \ bin \ 5.8 \ конфликт.dll (5.8)

Нет, это неправильно. Я бы посоветовал вам прочитать эту статью, чтобы узнать больше о том, какую эвристику использует CLR для исследования .

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

  1. Перекомпилируйте helper.dll, чтобы использовать последнюю версию conflict.dll (я определенно пойду с этим, если у меня будет исходный код для helper.dll).
  2. Выберите, какую версию conflict.dll вы хотите, и примените <bindingRedirect> в вашем конфигурационном файле. Например, если вы хотите использовать последнюю версию:

    <runtime>
        <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
            <dependentAssembly>
                <assemblyIdentity name="conflict"
                                  publicKeyToken="xxxxxxxxx"
                                  culture="neutral" />
                <bindingRedirect oldVersion="5.8.0.0" 
                                 newVersion="6.2.0.0" />
            </dependentAssembly>
        </assemblyBinding>
    </runtime>
    

Это будет эффективно инструктировать CLR загружать версию 6.2 conflict.dll при попытке разрешить ссылки для helper.dll. Обратите внимание, что если две версии строго подписаны разными ключами, этот метод не будет работать. Очевидно, что helper.dll был скомпилирован с версией 5.8, если у вас есть какие-либо различия (отсутствующие методы, разные сигнатуры методов), вы получите исключение времени выполнения при попытке вызвать конфликтующий метод, так что делайте это, только если вы абсолютно уверены в том, что делаете .

Вывод: независимо от того, какой путь вы выберете, вам придется xcopy в папке bin единственную версию conflict.dll.

1 голос
/ 06 сентября 2010

В поддержку ответа Дарина, конечно, вы должны устранить такие проблемы с несколькими версиями. Его решение использовать редирект связывания хорошее - +1 там. Я могу предложить решение, которое позволит вам сохранить оба, если это абсолютно необходимо, но вам придется написать немного кода.

Единственная реальная проблема, с которой вы здесь столкнулись, заключается в том, что два развернутых имени файла должны быть одинаковыми, чтобы загрузчик по умолчанию выбрал их. Вы могли бы ужасно обмануть и просто развернуть 5.8 dll как Conflict.exe, чтобы он мог сидеть рядом Conflict.dll (и новее), и вы обнаружите, что он работает.

Также, перейдя по ссылкам из ответа Дарина, вы попадаете на эту тему в теме MSDN о проверке . Основываясь на содержимом этого, вы можете просто развернуть dll 5.8 в bin \ Content \ Content.dll и, когда среда выполнения его ищет, он автоматически будет искать в этой подпапке.

Однако - это не очень хорошее решение:)

РЕДАКТИРОВАТЬ - НОВОЕ РЕШЕНИЕ

Если обе версии Conflict.dll уже подписаны, пытались ли вы на самом деле развернуть одну из версий с немного другим именем? Я только что настроил приложение winforms с двумя ссылками на разные версии одной и той же (подписанной) сборки. Это вызывает пару проблем со сборкой, потому что последняя версия, на которую ссылаются, будет развернута в папке bin, а другая - нет (поэтому вам придется вручную копировать в обе; переименовав одну из них соответственно). Затем я пытаюсь запустить приложение, которое отображает окно сообщения, содержащее две постоянные строки; по одному от каждой версии сборки. Работает абсолютно нормально.

Скачайте демонстрацию этого здесь - не собирайте его (в противном случае вам придется переименовать файл); просто откройте папку bin \ debug приложения формы и запустите exe.

ClassLibrary1.dll и ClassLibary1vanything.dll представляют собой v1.0.0.0 и v2.0.0.0 сборки с иным именем и открытым ключом. Несмотря на то, что classlibrary1vanything.dll имеет неправильное имя файла, он все еще работает (вероятно, потому что он подписан).

В app.config я вставил подсказку кодовой базы и подумал, что это сработало (изначально я развернул его под другим именем), но затем я закомментировал его, и оно все еще работало. Кодовая база, вероятно, наиболее полезна, когда сборка должна быть развернута в подпапке или в другом месте.

ОРИГИНАЛЬНЫЙ ТЕКСТ

Я пытался заставить работать второй из упомянутых вариантов в этой статье поддержки от MS , но, похоже, не хочет.

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

Если вы добавите свою собственную конфигурацию (возможно, только в appSettings) для полного имени сборки, которая будет привязана к другому имени файла, то в вашем обработчике события AssemblyResolve вы можете просмотреть имя сборки, которая должна быть загружена чтобы увидеть, если это в вашей конфигурации. Если это так, возьмитесь за местоположение и используйте Assembly.LoadFrom для его загрузки.

Таким образом, если у вас есть что-то подобное, вы просто добавляете туда запись для имени сборки Conflict v5.8 вместе с именем файла, которое должно использовать приложение.

Я не знаю, какой тип приложения вы развертываете, но в win-формах, консольных приложениях и службах AppDomain.CurrentDomain.BaseDirectory будет соответствовать папке bin, и вы можете присоединиться к ней с именем файла, который хотите загрузить , Сайты немного сложнее.

Должно работать угощение.

...