Несоответствие версии загрузки сборки: почему она загружается? - PullRequest
4 голосов
/ 04 мая 2011

У меня есть две сборки: HelloWorld.exe и Hello.dll.Exe является основной сборкой, а dll используется основной сборкой.

Я скомпилировал как HelloWorld.exe (1.0.0), так и Hello.dll (1.0.0).Я поместил сборки в другую папку.

Затем я изменил версию Hello.dll на 2.0.0 и переписал Hello.dll 1.0.0 версией 2.0.0.Затем я запускаю HelloWorld.exe, и он работает нормально.

Я ожидал, что он сразу аварийно завершит работу, потому что ссылка Hello.dll, когда я компилировал EXE-файл, была 1.0.0.Теперь библиотека 1.0.0 была заменена на 2.0.0, но она все еще работает!

Согласно MSDN :

По умолчанию сборка будетиспользуйте только типы из той же сборки (имя и номер версии), с которой она была собрана и протестирована.То есть, если у вас есть сборка, которая использует тип из версии 1.0.0.2 другой сборки, она (по умолчанию) не будет использовать тот же тип из версии 1.0.0.4 другой сборки.Такое использование имени и версии для идентификации ссылочных сборок помогает избежать проблемы «DLL-ада» при обновлении до одного приложения, которое нарушает работу других приложений.

Вопросы:

  1. Почемуэто работает?
  2. Как заставить его НЕ работать?
  3. БОНУСНЫЙ ВОПРОС: Что происходит во время процесса сборки?Разве версия внешних зависимостей не жестко закодирована в основную зависимость?

Обратите внимание, что Hello.dll не имеет строгого имени.

Вот манифест дляHelloWorld.exe:

// Metadata version: v2.0.50727
.assembly extern mscorlib
{
  .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )                         // .z\V.4..
  .ver 2:0:0:0
}
.assembly extern Hello
{
  .ver 2:0:0:0
}
.assembly HelloWorld
{
...//snipped
}

Вот журнал привязки сборки, взятый из Fuslogvw.exe (Средство просмотра журнала привязки сборки):

=== Pre-bind state information ===
LOG: User = ian.uy
LOG: DisplayName = Hello, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null
 (Fully-specified)
LOG: Appbase = file:///C:/Users/ian.uy/Desktop/HelloWorld/HelloWorld/bin/Debug/
LOG: Initial PrivatePath = NULL
LOG: Dynamic Base = NULL
LOG: Cache Base = NULL
LOG: AppName = NULL
Calling assembly : HelloWorld, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null.
===
LOG: This bind starts in default load context.
LOG: No application configuration file found.
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework\v2.0.50727\config\machine.config.
LOG: Policy not being applied to reference at this time (private, custom, partial, or location-based assembly bind).
LOG: Attempting download of new URL file:///C:/Users/ian.uy/Desktop/HelloWorld/HelloWorld/bin/Debug/Hello.DLL.
LOG: Assembly download was successful. Attempting setup of file: C:\Users\ian.uy\Desktop\HelloWorld\HelloWorld\bin\Debug\Hello.dll
LOG: Entering run-from-source setup phase.
LOG: Assembly Name is: Hello, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
LOG: Binding succeeds. Returns assembly from C:\Users\ian.uy\Desktop\HelloWorld\HelloWorld\bin\Debug\Hello.dll.
LOG: Assembly is loaded in default load context.

Ответы [ 3 ]

2 голосов
/ 04 мая 2011

Почему это работает?

Потому что вы так и указали;)

Как заставить его НЕ работать?

  1. Щелкните правой кнопкой мыши на DLL в Solution Explorer
  2. Выбрать Свойства
  3. Выбрать Использовать конкретную версию

БОНУСНЫЙ ВОПРОС: Что происходит в процессе сборки? Разве версия внешних зависимостей не жестко закодирована в основную зависимость?

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

1 голос
/ 12 мая 2017

Я сталкивался с тем же и пытался заглянуть в журналы msbuild:

msbuild /v:detailed /t:build

Интересными выглядят следующие строки:

Unified Dependency "Newtonsoft.Json, версия = 8.0.0.0, культура = нейтральная, PublicKeyToken = 30ad4fe6b2a6aeed». Использование этой версии вместо исходной версии "7.0.0.0" в "C: \ src \ BindingTest \ Lib1 \ bin \ Debug \ Lib1.dll", поскольку AutoUnify является 'Истинный'.

Кроме того, если вы извлечете полученный файл app.config после сборки, вы, вероятно, увидите там автоматическое перенаправление привязки, которого изначально не было в вашем app.config.

Таким образом, наблюдаемое нами поведение связано с процессами msbuild « автоматическое объединение сборок » и « автоматическое связывание ».

Вот что документация говорит о AutoUnify параметре:

Если true, результирующий граф зависимостей автоматически обрабатывается как если файл AppConfigFile был передан в файл App.Config параметр. Этот виртуальный файл App.Config имеет запись bindingRedirect для каждого конфликтующего набора сборок, так что самая высокая версия сборка выбрана. Следствием этого является то, что никогда не будет предупреждение о конфликтующих сборках, потому что каждый конфликт будет были решены.

Когда true, каждое отдельное переназначение приведет к высокому приоритету комментарий, показывающий старую и новую версии и что AutoUnify был верным.

Наконец, если вы хотите наблюдать «сбой», вы можете вызвать msbuild со следующими аргументами:

msbuild /v:d /t:build /p:AutoUnifyAssemblyReferences=false;AutoGenerateBindingRedirects=false
0 голосов
/ 25 июня 2018

Среда выполнения различает обычные и строгие сборки в целях управления версиями. Проверка версий происходит только со сборками со строгими именами.

https://docs.microsoft.com/en-us/dotnet/framework/app-domains/assembly-versioning

Для этого ответы следующие:

  1. Поскольку сборка не имеет строгого имени
  2. Сделать сборку со строгим именем
  3. Да, версии ссылочных сборок жестко запрограммированы. Вы можете проверить это с помощью декомпилятора (например, ILSpy), чтобы прочитать эту информацию
...