在.NET4库中使用ILMerge

在.NET4库中使用ILMerge,.net,dll,assemblies,c#-4.0,ilmerge,.net,Dll,Assemblies,C# 4.0,Ilmerge,两个问题: 1)基本.NET程序集未包含在合并的程序集中 从.NET3.5/VisualStudio2008升级到.NET4/VisualStudio2010后,我在后期构建中使用ILMerge时遇到问题。我有一个解决方案,其中几个项目的目标框架设置为“.NET framework 4”。我使用以下ILMerge命令将单个项目DLL合并到单个DLL中: if not $(ConfigurationName) == Debug if exist "C:\Program Files (x86)\

两个问题:

1)基本.NET程序集未包含在合并的程序集中

从.NET3.5/VisualStudio2008升级到.NET4/VisualStudio2010后,我在后期构建中使用ILMerge时遇到问题。我有一个解决方案,其中几个项目的目标框架设置为“.NET framework 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 framework目录的位置,我会从ILMerge中得到一个“未解析的程序集引用不允许:系统”错误。如果不指定MSTest目录的位置,则会出现“不允许未解析的程序集引用:Microsoft.VisualStudio.QualityTools.UnitTestFramework”错误

上面的ILMerge命令工作并生成DLL。然而,当我在另一个.NET 4 C#项目中引用该DLL并尝试在其中使用代码时,我得到以下警告:

无法解析主引用“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

编辑:除此之外,即使我在使用MyILMergedDLL.dll的使用者项目中添加了对
System.Xml
的引用,使用MyILMergedDLL.dll中的某些代码也会出现以下异常:

System.TypeLoadException:无法从程序集“MyILMergedDLL,版本=1.0.1.1,区域性=中性,PublicKeyToken=…”加载类型“System.Func”“2”

这是我的消费者项目中的代码;导致
TypeLoadException
的行是第二行:

var keys = new[] {"a", "b", "c"};
var row = new Row(keys);
抛出
TypeLoadException
的特定
构造函数是在
MyILMergedDLL
中的公共类中定义的,当我在引用单个项目DLL时使用此构造函数时,它可以正常工作。只有在引用IL合并DLL时使用此构造函数时,才会出现异常。我不知道发生了什么事

这是构造器:

public Row(IEnumerable<string> keys) : base(keys) { }
有一个解决x64问题的方法。如果您仍然有问题,请直接与Mike Barnett联系(微软网站的mbarnett)


增编。您的
/lib有一些非常非常错误的地方:“C:\Windows\Microsoft.NET\Framework64\v4.0.30319”
选项。最近,在.NET4.5发布后,这让许多程序员陷入了困境。该目录不是.NET 4.0引用程序集的正确目录。它的内容被4.5程序集覆盖,您不能再将其用于.NET 4.0安装。您得到的运行时错误非常棘手,程序无法再找到某些类型。通常在[Extension]属性上,有时在ICommand接口上

这些类型和其他一些类型从一个部件移动到另一个部件。使用正确的参考组件是一项严格的要求。您必须使用:

 /lib:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0"
调整以匹配您的特定计算机和目标框架版本。

以下是使用.NET 4.0的Visual Studio 2010 SP1的“生成后字符串”。我正在构建一个包含所有子.dll文件的console.exe

"$(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
基本提示:

  • 注意“\deploy\”目录:这是output.exe文件的结尾
  • 请注意“ILMerge\”目录。我将ILMerge实用程序复制到我的解决方案目录中(这样我就可以分发源代码,而不必担心记录ILMerge的安装)
高级提示:

如果它无法工作,请在“生成后”命令之前添加“echo”。然后,在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替换所有.exe+.dll文件。它还保持调试.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
其他备选方案:

  • (相当昂贵的商业替代品)

您还可以添加包含以下内容的配置文件:

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


摘自

只需在Visual Studio属性窗口中将PresentationCore和PresentationFramework引用设置为“Copy Local=True”(在解决方案资源管理器中选择引用后)。它将在不硬编码框架路径的情况下解决问题。我更喜欢此解决方案,因为路径根据开发人员/构建服务器是64位还是32位而有所不同,并且随着新的.NET/VS版本的发布不可避免地会发生变化。

对于那些在.csproj中使用的人:

<ILMerge InputAssemblies="@(MergeAssemblies)"
         ...
         TargetPlatformVersion="v4"
         TargetPlatformDirectory="$(ProgramFiles)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0"
/>


我们混合了CI构建代理,因此我们使用$(ProgramFiles)环境变量来指向正确的路径(驱动器+x86/x64文件夹),正如推荐的那样。

感谢您提供的信息。看了那页,我不知道发布的是什么:VS 2010、C#、.NET 4、ILMerge?没关系,在Mike Barnett的页面上翻找,我看到他在ILMerge上工作。:)对我没有下载任何新版本,但我仍将您的标记为正确的a
<ILMerge InputAssemblies="@(MergeAssemblies)"
         ...
         TargetPlatformVersion="v4"
         TargetPlatformDirectory="$(ProgramFiles)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0"
/>