【问题标题】:Unable to have NLog target working with an assembly generated through ILMerge无法让 NLog 目标处理通过 ILMerge 生成的程序集
【发布时间】: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 中删除/修改它们太深(但如果发生这种情况,我依靠我的持续集成服务器来警告我我破坏了某些东西)。

【问题讨论】:

    标签: c# nlog ilmerge


    【解决方案1】:
    <add assembly="MyTargets.NLog"/>
    

    将加载程序集“MyTargets.NLog”,使用TargetAttribute 搜索目标并注册它们。

    如果程序集与其他程序集合并,这将不起作用,因此我建议使用另一种方式将目标注册到 NLog。

    建议手动注册。尽快执行此操作,例如main(),或app_start

    Target.Register("MyTarget", typeof(MyNamespace.MyTarget)); 
    

    另请参阅:https://github.com/NLog/NLog/wiki/Register-your-custom-component

    【讨论】:

    • 朱利安您好,感谢您的回答。不幸的是,我必须避免修改针对 NLog 目标的应用程序,因此无法按照您的建议以编程方式注册目标。我不明白为什么不能通过典型的方式来做到这一点(如我的第一篇文章中所述),程序集合并不应阻止反射以使用 TargetAttribute 扫描类。您是否计划在未来的版本中对此进行改进?谢谢
    • &lt;add 上还有一个 assemblyFile 和 type 属性。也许这可以帮助你的情况?我们当然也想改进这一点,但不知道合并程序集如何影响扫描程序集。
    • 我检查了 type 和 assemblyFile 参数,但没有帮助。显然,程序集合并会阻止某些内部功能起作用,例如检查某种类型上存在的属性。我用我的发现和我最终为解决我的问题所做的工作对上述问题进行了重大更新。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-16
    相关资源
    最近更新 更多