Использование ILMerge с библиотеками .NET 4

Две проблемы:

1) Основная сборка .NET не включена в сборку с ILMerged

У меня возникли проблемы с использованием ILMerge в моей пост-сборке после обновления с .NET 3.5/Visual Studio 2008 до .NET 4/Visual Studio 2010. У меня есть решение с несколькими проектами, чья целевая структура установлена ​​на ".NET Рамки 4". Я использую следующую команду ILMerge для объединения отдельных DLL проектов в одну DLL:

if not $(ConfigurationName) == Debug
  if exist "C:\Program Files (x86)\Microsoft\ILMerge\ILMerge.exe"
    "C:\Program Files (x86)\Microsoft\ILMerge\ILMerge.exe"
      /lib:"C:\Windows\Microsoft.NET\Framework64\v4.0.30319"
      /lib:"C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\PublicAssemblies"
      /keyfile:"$(SolutionDir)$(SolutionName).snk"
      /targetplatform:v4
      /out:"$(SolutionDir)bin\development\$(SolutionName).dll"
      "$(SolutionDir)Connection\$(OutDir)Connection.dll"
      ...other project DLLs...
      /xmldocs 

Если я не укажу местоположение каталога платформы .NET 4, я получаю сообщение об ошибке "Неразрешенная ссылка на сборку: недопустимая: Система" от ILMerge. Если я не буду указывать местоположение каталога MSTest, я получаю сообщение об ошибке "Неразрешенная ссылка на сборку: ошибка Microsoft.VisualStudio.QualityTools.UnitTestFramework".

Команда ILMerge выше работает и создает DLL. Однако, когда я ссылаюсь на эту DLL в другом .NET.NET С#, и пытаюсь использовать код внутри нее, я получаю следующее предупреждение:

Основная ссылка "MyILMergedDLL" не может быть решена, поскольку она имеет косвенную зависимость от сборки .NET Framework "mscorlib, Version = 4.0, Culture = neutral, PublicKeyToken = b77a5c561934e089", которая имеет более высокую версию "4.0.65535.65535", чем версия "4.0.0.0" в текущей целевой структуре.

Если я удаляю флаг /targetplatform:v4 и пытаюсь использовать MyILMergedDLL.dll, я получаю следующую ошибку:

Тип "System.Xml.Serialization.IXmlSerializable" определен в сборке, на которую не ссылаются. Вы должны добавить ссылку на сборку "System.Xml, Version = 4.0.0.0, Culture = neutral, PublicKeyToken = b77a5c561934e089".

Кажется, я не должен был этого делать. Тот, кто использует мой MyILMergedDLL.dll API, не должен добавлять ссылки на любые библиотеки, на которые он ссылается. Как я могу обойти это?

2) TypeLoadException только при использовании объединенной сборки

Изменить:, даже если я добавлю ссылку на System.Xml в потребительский проект, в котором используется MyILMergedDLL.dll, использование некоторого кода в MyILMergedDLL.dll дает это исключение:

System.TypeLoadException: Не удалось загрузить тип 'System.Func`2' из сборки 'MyILMergedDLL, Version = 1.0.1.1, Culture = neutral, PublicKeyToken =...'.

Это код моего потребительского проекта; строка, которая вызвала TypeLoadException, является второй:

var keys = new[] {"a", "b", "c"};
var row = new Row(keys);

Конкретный конструктор Row, который выбрасывает TypeLoadException, определяется в открытом классе в MyILMergedDLL, и когда я использую этот конструктор при ссылке на отдельные DLL-проекты, он отлично работает. Только когда я использую этот конструктор при ссылке на объединенную DLL DL, я получаю исключение. Я не знаю, что происходит.

Здесь этот конструктор:

public Row(IEnumerable<string> keys) : base(keys) { }

И base, к которому он обращается, имеет этот код:

foreach (string key in keys.Where(
    key => !string.IsNullOrEmpty(key)
))
{
    _dic.Add(key, string.Empty);
}

Ответ 1

Для решения x64 проблемы возникла последняя версия. Немедленно свяжитесь с Майком Барнеттом, если у вас все еще есть проблемы (mbarnett at microsoft dot com).


Добавление. В вашем варианте /lib:"C:\Windows\Microsoft.NET\Framework64\v4.0.30319" есть что-то очень, очень неправильное. Это вызвало множество проблем с программистами в последнее время после выхода .NET 4.5. Этот каталог не для сборки ссылок .NET 4.0. Его содержимое перезаписывается с помощью 4.5 сборок, вы больше не можете использовать его для установки .NET 4.0. Ошибка выполнения, которую вы получаете, очень неудобна, программа больше не может найти определенные типы. Обычно бомбардирует атрибут [Extension], иногда на интерфейсе ICommand.

Эти типы и некоторые другие были перемещены из одной сборки в другую. Использование правильных эталонных сборок - это твердое требование. Вы должны использовать:

 /lib:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0"

Отрегулируйте соответствие вашей конкретной версии машины и целевой версии.

Ответ 2

Вот "Post Build String" для Visual Studio 2010 с пакетом обновления 1 (SP1), используя .NET 4.0. Я создаю консоль .exe со всеми включенными в нее суб-DLL файлами.

"$(SolutionDir)ILMerge\ILMerge.exe" /out:"$(SolutionDir)\deploy\$(TargetFileName)" "$(TargetDir)$(TargetFileName)" "$(TargetDir)*.dll" /target:exe /targetplatform:v4,C:\Windows\Microsoft.NET\Framework64\v4.0.30319 /wildcards

Основные советы:

  • Обратите внимание на каталог \"\\\\\\\\\\\\\\\\\\\\\\\\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
  • Обратите внимание на каталог "ILMerge \". Я скопировал утилиту ILMerge в свой каталог решений (чтобы я мог распространять исходный код, не беспокоясь о регистрации установки ILMerge).

Дополнительные советы:

Если у вас есть проблемы с неработоспособностью, добавьте "эхо" перед командой "Построить сборку". Затем откройте окно "Выход" в Visual Studio (View..Output) и проверьте точную команду, сгенерированную Visual Studio. В моем конкретном случае точная команда была:

"T:\PhiEngine\CSharp\ILMerge\ILMerge.exe" /out:"T:\PhiEngine\CSharp\Server Side\deploy\NfServiceDataHod.History.exe" "T:\PhiEngine\CSharp\Server Side\NfServiceDataHod\bin\Debug\NfServiceDataHod.History.exe" "T:\PhiEngine\CSharp\Server Side\NfServiceDataHod\bin\Debug\*.dll" /target:exe /targetplatform:v4,C:\Windows\Microsoft.NET\Framework64\v4.0.30319 /wildcards

Обновление

Добавил это на мой шаг "Построение сборки", он заменяет все файлы .exe +.dll одним комбинированным .exe. Он также сохраняет неповрежденный файл .pdb отладки:

rem Create a single .exe that combines the root .exe and all subassemblies.
"$(SolutionDir)ILMerge\ILMerge.exe" /out:"$(TargetDir)$(TargetName).all.exe" "$(TargetDir)$(TargetName).exe" "$(TargetDir)*.dll" /target:exe /targetplatform:v4,C:\Windows\Microsoft.NET\Framework64\v4.0.30319 /wildcards
rem Remove all subassemblies.
del *.dll
rem Remove all .pdb files (except the new, combined pdb we just created).
ren "$(TargetDir)$(TargetName).all.pdb" "$(TargetName).all.pdb.temp"
del *.pdb
ren "$(TargetDir)$(TargetName).all.pdb.temp" "$(TargetName).all.pdb"
rem Delete the original, non-combined .exe.
del "$(TargetDir)$(TargetName).exe"
rem Rename the combined .exe and .pdb to the original name we started with.
ren "$(TargetDir)$(TargetName).all.pdb" "$(TargetName).pdb"
ren "$(TargetDir)$(TargetName).all.exe" "$(TargetName).exe"
exit 0

Ответ 4

Вы также можете добавить файл конфигурации со следующим:

<?xml version ="1.0"?>
<configuration>
  <startup useLegacyV2RuntimeActivationPolicy="true">
    <requiredRuntime safemode="true" imageVersion="v4.0.30319" version="v4.0.30319"/>
  </startup>
</configuration>

Взято из здесь

Ответ 5

Просто установите ссылки PresentationCore и PresentationFramework на наличие "Копировать локальное = True" в окне свойств Visual Studio (после выбора ссылок в обозревателе решений). Это решит проблему без жесткого кодирования каркасного пути. Я предпочитаю это решение, потому что путь отличается в зависимости от того, является ли сервер разработчика/сборки 64-битным или 32-битным и неизбежно изменится по мере выпуска новых версий .NET/VS.