简体   繁体   中英

Compiling C# code at runtime under mono fails when referencing Newtonsoft.Json.dll

our software is written in C# running .Net-Framework 4.7.2 . Our users can use a script editor built into our software to write their own user scripts with C#. To realize that, we are using the .Net component CodeDomProvider . To make it possible to work with JSON in an easy way, we want to make Newtonsoft.Json.dll be referenced in our user's scripts. This is done by adding the reference to the CompilerParameters of the CodeDomProvider. The Newtonsoft.Json is added to my application by the usage of the newest Newtonsoft.Json NuGet package (12.0.3).

Here a minimum example of this setup:

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();
        }
    }
}

This setup works fine under .Net Framework on Windows. The problem is, that we are also providing a version of our software running with Mono on (Arch)-Linux (Linux 4.19.80-1-ARCH armv7l, Mono JIT compiler version 6.0.0 (makepkg/6256b82d62f Wed 25 Sep 2019 05:04:08 AM UTC)), where running the same code with mono results in an error CS0006: Metadata file Newtonsoft.Json.dll could not be found .

I already tried to add the following to the app.conf of my application, but that did not help. Also reinstalling the NuGet package did not help. Adding the Newtonsoft.Json.dll to the GAC does not work (fails with Failure adding assembly Newtonsoft.Json.dll to the cache: The file specified is not a valid assembly. ). While trying around with the app.conf I observed the error message changed to error CS0009: Metadata file /opt/Newtonsoft.Json.dll does not contain valid metadata: Metadata file /opt/Newtonsoft.Json.dll does not contain valid metadata . That's why I guess he finds the dll but needs additional, valid meatadata. I thought about some sort of 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>

Does anyone have a hint on how to get this to work?

You have two possibilites:

  1. Use latest Mono (6.6) from github. Compile it if package not avaliable.

  2. Downgrade Newtonsoft.Json to version 11.0. Use binding redirect if nessecary.

Your code example works well on .NET 4.7, but since you're running Mono here are some possible solutions for you:

Compiler needs to know where to get this file.
If you say that you need to reference System.dll - compiler probably tries to find it in GAC (and it does find it).
When you reference unknown library like Newtonsoft.Json.dll it tries to search GAC and fails. Then it's probably trying to find it in working directory, etc ..

Solution #1:

Try to set full path to your library;

Solution #2:

Try to register Newtonsoft.Json.dll in the GAC;

Solution #3:

Try .NET Core! It's amazing, cross-platform and 3.1 version now has open source WinForms and WPF!

I know that moving your code to .NET Core 3 takes time but still it's worth it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM