Использование нескольких версий одной и той же DLL - PullRequest
24 голосов
/ 07 мая 2011

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

Однако в моих библиотеках DLL я хотел бы использовать новую версию внешней библиотеки DLL (над которой у меня нет контроля). Если я просто ссылаюсь на новую DLL и работаю только с этой, мой код будет работать, но старый код перестанет работать.

Could not load file or assembly 'itextsharp, Version=5.0.6.0, Culture=neutral,
PublicKeyToken=8354ae6d2174ddca' or one of its dependencies. The located assembly's
manifest definition does not match the assembly reference. (Exception from HRESULT:
0x80131040)

Я пытался изменить трюк с именем DLL, но это было слишком наивно для меня, чтобы думать, что это сработает. Я пытался использовать внешние псевдонимы (определяя их в своих ссылках), но я все еще не знаю, как поместить два файла с одинаковым именем в одну папку BIN ...

Что мне делать?

Ответы [ 5 ]

15 голосов
/ 07 мая 2011

Вы можете загрузить другую версию в определенный домен приложений

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

http://msdn.microsoft.com/en-us/magazine/cc164072.aspx

В очень простом смысле это сводится к примеру кода:

    AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
    ...

    static System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
    {
        if (/*some condition*/)
            return Assembly.LoadFrom("DifferentDllFolder\\differentVersion.dll");
        else
            return Assembly.LoadFrom("");
    }
10 голосов
/ 10 мая 2018

Предположим, у вас есть следующая структура проекта:

Project Diagram

... где A и B - библиотеки классов, а C - исполняемый файлТип проекта (например, модульное тестирование или консольный проект).

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

ABC.sln
A/A.csproj
A/...
B/B.csproj
B/...
C/C.csproj
C/...
lib/thirdparty4/thirdparty.dll
lib/thirdparty5/thirdparty.dll

Если бы мы попытались наивно ссылаться на наши проекты вместе, у нас возникла бы проблема: две версии thirdparty.dll будут скопированыв ту же папку (выходной каталог (т. е. bin) C).Нам нужен способ для C скопировать обе библиотеки в свой выходной каталог и предоставить механизм для ссылки на любой из них.

Чтобы решить эту проблему, я изменил C.csproj, чтобы он содержал следующее:

<ItemGroup>
  <Content Include="..\lib\thirdparty4\thirdparty.dll">
    <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    <Link>thirdparty4\thirdparty.dll</Link>
  </Content>
  <Content Include="..\lib\thirdparty5\thirdparty.dll">
    <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    <Link>thirdparty5\thirdparty.dll</Link>
  </Content>
</ItemGroup>

Это даст ему указание создать thirdparty4\thirdparty.dll и thirdparty5\thirdparty.dll в своем выходном каталоге.

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

C\bin\Debug\A.dll
C\bin\Debug\B.dll
C\bin\Debug\C.dll
C\bin\Debug\thirdparty4\thirdparty.dll
C\bin\Debug\thirdparty5\thirdparty.dll

Чтобы указать C использовать оба эти dll, я добавил файл App.config вэто со следующим:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="thirdparty" culture="neutral" publicKeyToken="1234567890123445"/>
        <bindingRedirect oldVersion="4.0.0.0-4.0.0.0" newVersion="4.0.0.0" />
        <codeBase version="4.0.0.0" href="thirdparty4\thirdparty.dll" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="thirdparty" culture="neutral" publicKeyToken="1234567890123445"/>
        <bindingRedirect oldVersion="5.0.0.0-5.0.0.0" newVersion="5.0.0.0" />
        <codeBase version="5.0.0.0" href="thirdparty5\thirdparty.dll" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
</configuration>

Это даст указание сборке, в зависимости от того, какая версия требуется, использовать одну DLL или другую, обе из которых будут доступны в подпапках выходного каталога.(Элементы bindingRedirect являются необязательными, но вы можете использовать их, если вам нужен диапазон ревизий для этого применения.)

5 голосов
/ 29 июня 2012

Другой возможный вариант - использовать extern, как описано здесь:

http://blogs.msdn.com/b/abhinaba/archive/2005/11/30/498278.aspx

3 голосов
/ 01 марта 2018

Если решение AppDomains не применимо в вашем случае, у вас нехватка времени, у вас есть противоречивые требования (например, , когда когда-либо случается), и вы не против смехотворно вымышленных хаков:

  • Декомпилируйте более новую версию сборки с помощью инструмента ildasm (часть командной строки разработчика, включенная в Visual Studio)
  • Отредактируйте сгенерированный файл .il, чтобы найти / заменитьссылки на пространство имен сборки.В приведенном примере это будет изменение с itextsharp.X на itextsharp.new.X
  • Аналогичным образом отредактируйте значение для AssemblyTitleAttribute.Это требует перевода символов ASCII в шестнадцатеричный формат.
  • Перекомпилируйте файл .il, используя ilasm
  • Обратите внимание, что это может потребоваться повторить для любых зависимых сборок (например, someassembly.core.wh независимо)
  • Добавьте новые .dll в ваш проект с другим именем и ссылайтесь на них явно (а не через nuget или что-либо еще)

Эй, не смотритеу меня так.Я сказал нелепо придуманный хак ...

1 голос
/ 07 мая 2011

Вы также можете положиться на перенаправление привязки сборки для сборки со строгим именем, как описано в http://msdn.microsoft.com/en-us/library/2fc472t2.aspx.

У вас будет только одна версия файла (самая последняя), и обе ссылки разрешат ее.

...