【发布时间】:2018-05-20 13:53:29
【问题描述】:
我用自定义 TargetWithLayout 编写了一个自定义程序集,我们称之为 MyTargets.NLog.dll,目标为 MyTestTarget。
当我加载它并使用它时使用
<extensions>
<add assembly="MyTargets.NLog"/>
</extensions>
并且在部分中。
<target name="my" type="MyTest" />
完美运行。我可以从我的程序中使用它。顺便说一句:.Net 4.6.2 和 NLog 4.5.3
但是我的程序集有点不方便:它依赖于其他一些程序集,我想将它放在一个文件中。
所以我使用 ILMerge 来生成一个单独的程序集,但它没有按预期工作。我不使用特定选项,只是“复制属性”。
如果我使用“合并”程序集而不是原始程序集,在运行时我得到:
NLog.config failed. Exception: NLog.NLogConfigurationException: Exception when parsing ...NLog.config. ---> System.ArgumentException: Target cannot be found: 'MyTarget'
à NLog.Config.Factory`2.CreateInstance(String name)
à NLog.Config.XmlLoggingConfiguration.ParseTargetsElement(NLogXmlElement targetsElement)
à NLog.Config.XmlLoggingConfiguration.ParseNLogElement(NLogXmlElement nlogElement, String filePath, Boolean autoReloadDefault)
à NLog.Config.XmlLoggingConfiguration.ParseTopLevel(NLogXmlElement content, String filePath, Boolean autoReloadDefault)
à NLog.Config.XmlLoggingConfiguration.Initialize(XmlReader reader, String fileName, Boolean ignoreErrors)
--- Fin de la trace de la pile d'exception interne ---
我知道程序集本身加载良好,因为错误与目标有关。 (如果程序集本身丢失,我应该有类似的东西: 加载扩展时出错:MyTargets.NLog ---> 无法加载文件或程序集“MyTargets.NLog”或其依赖项之一。系统找不到指定的文件。)
我已经用反编译器 (dotPeek) 进行了检查:目标存在于两个程序集中,“原始”一个和合并的一个,完全相同定义相同:
namespace MyTargets.NLog.Targets
{
[Target("MyTest")]
public class MyTestTarget : TargetWithLayout
{
...
}
}
使用反编译器,我还可以看到嵌入在合并程序集中的所有其他程序集:我的所有依赖项(如预期的那样),还有 NLog 程序集本身(因为它被引用为项目的依赖项)。
您是否知道什么可以阻止 NLog 从合并的 dll 中加载目标,即使该类已存在? 是否与 ILMerged 也将整个 NLog 包重新集成在其中有关(我在 ILMerge 中找不到阻止它的方法)。
谢谢
----- UPDATE 基于 Julian 的评论:
你提到参数“type”和“assemblyFile”的存在。 我没有在文档中找到它(https://github.com/nlog/nlog/wiki/Register-your-custom-component)。 但你是对的,它们存在:https://github.com/NLog/NLog/blob/master/src/NLog/Config/XmlLoggingConfiguration.cs 不幸的是,“类型”参数用于当前(NLog 程序集),而不是“程序集”属性中指定的自定义程序集。见第 1039 行。 即使我的程序集没有合并,对我的情况也无济于事。
所以我尝试修改和重建 NLog,通过添加一个在参数中同时接受“类型”和“程序集”的方法,并且这个调用是否受到记录器配置加载中现有案例的启发:
Assembly asm = AssemblyHelpers.LoadFromName(assemblyName);
var loadedType = asm.GetType(type, true, false);
ConfigurationItemFactory.RegisterType(loadedType, prefix);
该方法没有抛出任何错误,类型已成功加载,但我的目标仍然不可用。
我已经深入挖掘,发现 TargetAttribute 的 IFactory 不允许注册我的类,因为它没有找到所需的 Target 属性。显然,
loadedType.GetCustomAttributes<TargetAttribute>(false)
没有找到(尽管类上有对应的属性)。还有
loadedType.GetCustomAttributes<Attribute>(true)
使用 TargetAttribute 找到它。
所以我的猜测是“运行时”nlog 程序集和“合并”程序集中 TargetAttribute 的重复定义会阻止反射在搜索特定属性时正常工作,因为它们是在两个地方定义的。
也许这里的解决方案之一:Is it possible to only merge a subset of dependencies using ILMerge? 可能会有所帮助(通过从输出程序集中排除 NLog),但我没有太多时间进行测试。
-----最终“解决方案”:
所以我选择了一个完全不同的解决方案:由于程序集合并不是一个选项,我从我的 NLog 自定义库中删除了所有依赖项,并直接将所需的外部文件导入为“links” Visual Studio(在添加现有文件窗口中,对于那些从未做过的人,使用打开按钮左侧的小箭头)。所以我不再需要相关的程序集。 我只需要注意不要在原始 DLL 中删除/修改它们太深(但如果发生这种情况,我依靠我的持续集成服务器来警告我我破坏了某些东西)。
【问题讨论】: