使用Mono在运行时编译C#代码时,引用Newtonsoft.Json.dll会导致失败。

4
我们的软件是用C#编写的,运行在.Net-Framework 4.7.2上。我们的用户可以使用内置的脚本编辑器编写自己的C#用户脚本。为了实现这一点,我们使用了CodeDomProvider .Net组件。为了方便地处理JSON,我们希望在我们的用户脚本中引用 Newtonsoft.Json.dll。这可以通过将其添加到CodeDomProvider的CompilerParameters来实现。最新版本的Newtonsoft.Json NuGet包(12.0.3)已被添加到我的应用程序中。以下是这种设置的最简示例:
using System;
using System.CodeDom.Compiler;
using System.IO;

namespace ScriptingUnix
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                string output;
                if (Environment.OSVersion.Platform == PlatformID.Unix)
                {
                    output = "/tmp/MyUnixTest.dll";
                }
                else
                {
                    output = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "MyUnixTest.dll");
                }

                CompilerParameters parameters = new CompilerParameters
                {
                    GenerateInMemory = false,
                    IncludeDebugInformation = true,
                    OutputAssembly = output
                };

                using (CodeDomProvider codeProvider = CodeDomProvider.CreateProvider("CSharp"))
                {
                    parameters.ReferencedAssemblies.Add("System.dll");
                    parameters.ReferencedAssemblies.Add("Newtonsoft.Json.dll");
                    CompilerResults results = codeProvider.CompileAssemblyFromSource
                    (
                        parameters, 
                        "using System;\nusing Newtonsoft.Json.Serialization;\nusing Newtonsoft.Json.Linq;\n class Program\r\n{\r\n    static void Main(string[] args)\r\n    {\r\n        \r\n    }\r\n}"
                    );

                    foreach (CompilerError compilerError in results.Errors)
                    {
                        Console.WriteLine(compilerError);
                    }
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }
            Console.ReadLine();
        }
    }
}

此设置在Windows的.Net Framework下运行良好。问题是,我们还提供了在(Arch)-Linux(Linux 4.19.80-1-ARCH armv7l,Mono JIT编译器版本6.0.0(makepkg/6256b82d62f于2019年9月25日星期三上午05:04:08 UTC))上运行Mono版本的软件,在此版本下使用mono运行相同的代码会导致错误CS0006:找不到元数据文件Newtonsoft.Json.dll。
我已经尝试将以下内容添加到应用程序的app.conf中,但没有帮助。重新安装NuGet包也没有帮助。将Newtonsoft.Json.dll添加到GAC不起作用(失败并显示“将程序集Newtonsoft.Json.dll添加到缓存时出错:指定的文件不是有效的程序集。”)。在尝试app.conf时,我观察到错误消息更改为“错误CS0009:元数据文件/opt/Newtonsoft.Json.dll不包含有效的元数据:元数据文件/opt/Newtonsoft.Json.dll不包含有效的元数据”。这就是我猜他找到了dll但需要额外的有效元数据。我想到了某种类型的dll.conf。
<runtime>
  <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
    <dependentAssembly>
      <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral"/>
      <bindingRedirect oldVersion="0.0.0.0-12.0.0.0" newVersion="12.0.0.0"/>
    </dependentAssembly>
  </assemblyBinding>
</runtime>

有没有人对如何使这个工作有提示?

2个回答

4

您有两种选择:

  1. 使用来自Github的最新版Mono(6.6)。如果包不可用,则编译它。

  2. 将Newtonsoft.Json降级到11.0版本。如果需要,使用绑定重定向。


你认为这会解决问题吗?与Mono 6.0.0或Newtonsoft.Json 11.0到12.0.3相比,Mono 6.6有哪些变化应该改变了行为? - Soloresq
因为我已经测试过了,这解决了问题。可能dll格式已经改变,新的mono已经添加了对新格式的支持。 - Andrus
我刚刚使用11.0.2重新测试了它,并进行了绑定重定向到<bindingRedirect oldVersion="0.0.0.0-12.0.0.0" newVersion="11.0.0.0" />。现在它按预期工作了。非常感谢@Andrus。 - Soloresq
在我的情况下,必须使用Newtonsoft.Json 12。将容器中的mono更新到最新版本(6.8)。现在又可以工作了。太好了!很高兴我找到了这个线程!谢谢。 - Chuck Kasabula

0

你的代码示例在 .NET 4.7 上运行良好,但由于你正在运行 Mono,因此这里有一些可能的解决方案:

编译器需要知道从哪里获取该文件。
如果你说你需要引用 System.dll - 编译器可能会尝试在GAC中查找它(并且确实找到了)。
当你引用未知库,如 Newtonsoft.Json.dll 时,它会尝试搜索 GAC 并失败。然后它可能会尝试在工作目录中找到它,等等

解决方案 #1:

尝试设置库的完整路径;

解决方案 #2:

尝试在 GAC 中 注册 Newtonsoft.Json.dll

解决方案 #3:

试试 .NET Core 吧!它很棒,跨平台,现在的 3.1 版本还有开源的 WinForms 和 WPF!

我知道将你的代码迁移到 .NET Core 3 需要时间,但这仍然是值得的。


从错误信息来看,我猜他找到了Newtonsoft.Json.dll,但他想要一些额外的元数据。我也尝试将dll添加到GAC中,但gacutil报告:将程序集Newtonsoft.Json.dll添加到缓存时失败:指定的文件不是有效的程序集。计划切换到.net Core,但目前还不可行,所以这对我来说不是一个解决方案。根据您的评论更新问题。 - Soloresq

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接