合并程序集中的 .NET 类型定义 (ILMerge)
我正在使用 ILMerge 合并多个 .NET 程序集,包括一些第 3 方程序集。自从这样做以来,我遇到了几个错误,这些错误都归结为类型定义与定义它们的程序集绑定在一起的事实。
一个简单的例子是我的 App.config 中的 log4net config 部分定义。它使用 type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" ,这将不起作用,因为 log4net 程序集在合并到我的合并程序集后就不存在。不过没什么大不了的,我将程序集名称更改为合并后的程序集,并且工作正常。
一个稍微复杂的例子是二进制序列化类型。我的系统使用二进制序列化在进程之间发送某些对象。所有可序列化对象都在所有其他项目引用的公共程序集中定义。我使用的是默认的二进制序列化,但在反序列化对象时开始失败,并出现错误,指出找不到序列化对象的合并程序集。同样,没什么大不了的,我实现了一个自定义 SerializationBinder,它在任何加载的程序集中查找类型,而不仅仅是给定的类型。
当序列化类型引用其他可序列化类型时,前面的示例会变得更加复杂。我继续遇到越来越多的问题,而且越来越难以处理。
我在这里想要表达的一点是,.NET 类型系统和 ILMerge 似乎不能很好地协同工作。有谁有解决这个问题的经验吗?是否可以告诉 .NET 运行时我不关心该类型应该位于哪个程序集中,只需在任何地方查找它即可?
注意:请不要回答询问我为什么要合并程序集,这不是这个问题的重点。
I am merging several .NET assemblies using ILMerge including some 3rd party assemblies. Since doing so, I've experienced several errors that all boil down to the fact that type definitions are tied to the assembly they are defined in.
A simple example is the log4net config section definition in my App.config. It uses type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" which will not work since the log4net assembly does not exist once it has been merged into my merged assembly. Not a big deal though, I change the assembly name to my merged assembly and it works fine.
A slightly more complicated example is binary serialized types. My system uses binary serialization to send certain objects between processes. All of the serializable objects are defined in a common assembly that all of the other projects reference. I was using the default binary serialization, but it started failing when deserializing the objects with the error stating that it could not find the merged assembly that serialized the object. Again, not a big deal, I implemented a custom SerializationBinder that looks for the type in any loaded assembly, not just the one given.
The previous example got more complicated when the serialized type reference other serializable types. I've continued to run into more and more problems that are getting increasingly difficult to deal with.
The point I'm trying to get at here is that the .NET type system and ILMerge don't appear to play well together. Does anyone have any experience with how they have solved this problem? Is it possible to tell the .NET runtime that I don't care what assembly the type says it should be in, just look for it anywhere?
NOTE: Please do not reply asking why I'm merging assemblies, that is not the point of this question.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
问题发生几年后,我遇到了同样的问题并找到了解决方案。您可以将
[assemble: log4net.Config.XmlConfigurator(ConfigFile = "logging.config", Watch = true)]
添加到 AssemblyInfo.cs 文件中,这将在合并 log4net 程序集时起作用。Several years after the question, I came across the same issue and found a solution. You can add
[assembly: log4net.Config.XmlConfigurator(ConfigFile = "logging.config", Watch = true)]
in to the AssemblyInfo.cs file and this will work when merging the log4net assembly.欢迎来到代码中字符串和(物理位置)字符串的危险。
所有此类工具都有类似的问题,它们最好是聪明的,因为绑定和序列化等运行时功能的许多开发人员和设计人员并没有真正预见到这一点,但是他们确实将 ILMerge 推崇为“智能”工具。它非常聪明,甚至无法修剪类型。
请注意,版本控制在这里也发挥了作用,配置、.* 和他们眼中的明星以及 Redmond 的版本独立性也无济于事。
您肯定会不断遇到第三方位的麻烦。相信我,我知道你需要合并,因为一些可悲的少量类型可能需要很长时间才能让 MS JIT 启动大型应用程序(不,我不希望 NGEN 或优化的 3.5SP1 加载比以前更慢由于 System.Core 或天上禁止的 WPF 膨胀)。
恕我直言,至少在大规模上,最好的选择是获得一个像样的商业工具来扫描和处理这个问题(即从现有的痛苦和混淆经验中)。从长远来看,如果您没有源代码,您可能最终会检测现有的 IL 代码。
[ 然后有一个 INotifyPropertyChanged 字符串发明,解决了全球变暖问题 - 由 Casio-Calc 发明家设计 ]
Welcome to perils of strings and (physical-location) strings in code..
All tools of that kind have similar problems and they better be smart, as many devs and designers of runtime features such as binding and serialisation didn't really envisage it but they sure pushed ILMerge as a 'smart' tool. It's so smart it can't even prune types.
Note that versioning also comes into play here, and configuration, .* and stars-in-their-eyes, and version independence from Redmond does not help either.
You will keep hitting trouble with thirdy party bits for sure. And believe me, I know you need the merging, as some pathetic small number of types can take ages for MS JIT to kick in for large apps (and nope, I don't want NGEN or optimised 3.5SP1 loading that's even slower than before due to System.Core or heaven-forbid WPF bloat ).
Best option, imho, at least on a large scale, is to get a decent commercial tool that scans and handles this (ie. from the existing pain and obfuscation experience out there). In the long run, you might end up instrumenting existing IL code if you don't have the sources.
[ Then there was a INotifyPropertyChanged string invention that so solved the global warming problem - Designed by Casio-Calc Inventors ]
是的,这个问题有一个解决方案:构建模块而不是程序集!
.net 编译器有一个选项(C# 和 VB 的 /target:module),用于构建模块而不是程序集。然后可以将多个模块传递给编译器并用于构建最终的程序集。
当然,这一切都假设您已经获得了这些第 3 方程序集的源代码。如果您无法获得该信息,也许可以从第 3 方购买第 3 方程序集的 .netmodule 版本?
如果这不起作用,您还有最后一个选择。显然,您已经将第 3 方程序集拆解为 IL。从该 IL 文件中删除程序集信息并使用“ilasm /dll”构建一个 .net 模块,您现在应该能够像使用任何其他 .net 模块一样使用它!
通过使用模块而不是程序集,您不应该再遇到任何基于程序集的问题。
确实,我们已经通过不再使用 ILMerge 解决了您的 ILMerge 问题,但这难道不是最好的解决方案吗?
希望它对您有用,这里有一些方便的链接:
.netmodule 而不是程序集
ILASM 与 .netmodules
(在这里我想我对 .netmodules 的体验永远不会对任何人都有用!)
Yes, there is a solution to this problem: Build modules instead of assemblies!
Compilers for .net have an option (/target:module for C# and VB) that builds a module instead of an assembly. Multiple modules can then be passed to the compiler and used to build the final assembly.
Of course, this all assumes that you've got the source to those 3rd party assemblies. If you can't get that, perhaps a .netmodule version of the 3rd party assembly can be procured from the 3rd party?
If that won't work, you've still got one last option. Obviously you're already disassembling a 3rd party assembly into IL. Strip out the assembly information from that IL file and use "ilasm /dll" to build a .netmodule which you should now be able to use just like any other .netmodule!
By using modules instead of assemblies you shouldn't have any more assembly-based issues.
True, we've solved your problem with ILMerge by not using ILMerge anymore, but isn't that really the best solution?
Hope it works for you, here's some handy linkage:
.netmodule instead of assembly
ILASM with .netmodules
(And here I was thinking that my experience with .netmodules would never be useful to anyone!)