Поменять сильно подписанную сборку во время выполнения - PullRequest
3 голосов
/ 02 января 2012

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

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

"Определение манифеста обнаруженной сборки не соответствует ссылке на сборку"

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

Я думал, что перенаправление привязки может помочь мне, но у него есть недостаток, заключающийся в том, что вы не можете указать диапазон "новых версий". Любая комбинация должна работать, старше с новой версией и наоборот.

 <bindingRedirect oldVersion="1.2.7.0" newVersion="1.2.8.0" /> 

http://msdn.microsoft.com/en-us/library/eftw1fys.aspx

Я также смотрел на динамический вызов, но затем я теряю безопасность типов (мой код широко использует типы, определенные в сторонней сборке). -> Удалить ссылку сложно.

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

<Reference Include="<assemblyname>">
  <SpecificVersion>False</SpecificVersion>
  <HintPath>..\..\Dependencies\<manufacturer>\1.2.7.0\<assemblyname>.dll</HintPath>
</Reference>

Примечание: Логика загрузки и выгрузки сборок во время выполнения уже существует. Для сторонней библиотеки нет интерфейса

1 Ответ

1 голос
/ 27 июня 2013

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

Внутри обработчика событий вам нужно проверить свойство ResolveEventArgs.Name, чтобы увидеть, является ли сборка той, которую вам нужно загрузить. Свойство Name будет длинным именем загружаемой сборки - то есть «Widget.Net, версия = 1.2.3.4, Culture = нейтральный, PublicKeyToken = xxxxxxxxxxx».

После определения правильного запроса на загрузку просто загрузите правильную версию сборки ( Assembly.LoadFrom , Assembly.Load, Assembly.LoadWithPartialName) и верните ее из обработчика событий. Обратите внимание, что Assembly.LoadWithPartialName помечен как устаревший, но, похоже, это единственный способ решить эту проблему, если целевая сборка находится в GAC.

// application initialization
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;

private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
    if (args.Name.StartsWith("Widget.Net, Version="))
    {
        Assembly result = Assembly.LoadFrom("Widget.Net.dll");
        return result;
    }
    return null;
}

Важно знать, что хотя это «решает» проблему, это ни в каком смысле не является хорошим решением. Он полностью подрывает обычную версию и проверку строгого имени сборок, используемых .Net Framework. Это то, что вы делаете, когда у вас нет другого выбора, потому что (как в вопросе) поставщик испортил версию своей сборки. Вы также полагаетесь на то, что они не вносят существенных изменений в классы, определенные в сборке между указанной версией и загруженной версией, то есть все используемые вами классы, свойства, методы и т. Д. Все еще существуют и имеют одинаковые подписи.

Чтобы сохранить хотя бы видимость безопасности, было бы неплохо хотя бы проверить в обработчике событий AssemblyResolve, что:

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