两个问题:
1) Basic .NET Assembly Not Included in ILMerged Assembly
从.NET 3.5 / Visual Studio 2008升级到.NET 4 / Visual Studio 2010后,我在后期构建中使用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框架目录的位置,我会从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 Only When Using Merged Assembly
Edit: 超出此范围,即使我在使用MyILMergedDLL.dll的使用者项目中添加对 System.Xml
的引用,使用MyILMergedDLL.dll中的某些代码也会产生以下异常:
System.TypeLoadException:无法从程序集'MyILMergedDLL,Version = 1.0.1.1,Culture = neutral,PublicKeyToken = ...'加载类型'System.Func`2' .
这是我的消费者项目中的代码;导致 TypeLoadException
的行是第二行:
var keys = new[] {"a", "b", "c"};
var row = new Row(keys);
抛出 TypeLoadException
的特定 Row
构造函数在 MyILMergedDLL
中的公共类中定义,当我在引用单个项目DLL时使用此构造函数时,它可以正常工作 . 只有在我引用IL合并的DLL时才使用此构造函数,我才会获得异常 . 我不知道怎么回事 .
这是构造函数:
public Row(IEnumerable<string> keys) : base(keys) { }
它所引用的 base
具有以下代码:
foreach (string key in keys.Where(
key => !string.IsNullOrEmpty(key)
))
{
_dic.Add(key, string.Empty);
}
6 回答
有一个very recent release来解决x64问题 . 如果您仍有问题,请直接与Mike Barnett联系(mbarnett at microsoft dot com)
附录 . 你的
/lib:"C:\Windows\Microsoft.NET\Framework64\v4.0.30319"
选项有一些非常非常错误的东西 . 在.NET 4.5发布之后,最近很多程序员都遇到了麻烦 . 该目录是 not 适用于.NET 4.0参考程序集的目录 . 其内容被4.5程序集覆盖,您无法再使用它来定位.NET 4.0安装 . 你得到的运行时错误非常尴尬,程序再也找不到某些类型了 . 通常在[Extension]属性上进行轰炸,有时在ICommand接口上进行 .这些类型和其他一些类型从一个程序集移动到另一个程序集 . 使用正确的参考组件是一项艰巨的要求 . 你 must 使用:
调整以匹配您的特定计算机和目标框架版本 .
这是使用.NET 4.0的Visual Studio 2010 SP1的“Post Build String” . 我正在构建一个包含所有子.dll文件的控制台.exe .
Basic hints:
注意"\deploy"目录:这是输出.exe文件的最终位置 .
注意"ILMerge"目录 . 我将ILMerge实用程序复制到我的解决方案目录中(因此我可以分发源代码而不必担心记录ILMerge的安装) .
Advanced hints:
如果您遇到问题,请在“Post Build”命令之前添加“echo” . 然后,在Visual Studio中打开“输出”窗口(View..Output),并检查Visual Studio实际生成的确切命令 . 在我的特定情况下,确切的命令是:
Update
将此添加到我的“Post Build”步骤中,它用一个组合的.exe替换所有.exe .dll文件 . 它还保持调试.pdb文件完好无损:
其他选择:
Combining multiple assemblies into a single EXE for a WPF application .
.Net Reactor .
SmartAssembly(一种相当昂贵的商业替代品) .
您还可以使用以下内容添加配置文件:
摘自here
只需将PresentationCore和PresentationFramework引用设置为在Visual Studio属性窗口中具有“Copy Local = True”(在解决方案资源管理器中选择引用之后) . 它将在不对框架路径进行硬编码的情况下解决问题 . 我更喜欢这种解决方案,因为路径是不同的取决于开发人员/构建服务器是64位还是32位,并且随着新的.NET / VS版本的发布不可避免地会发生变化 .
对于那些在.csproj中使用ILMerge from community tasks的人:
我们有CI构建代理的混合园区,因此我们使用$(ProgramFiles)环境变量来指向正确的路径(驱动器x86 / x64文件夹),因为它是MSBuild Team推荐的 .