I have a project that uses some dynamically compiled code and I am upgrading from .net framework to .net core 3.1.
I can't get a simple test case to include newtonsoft.json.dll and get the error "Type or namespace name 'Newtonsoft' could not be found. I had a similar problem when I first tried add the library, but got past it by using the currently loaded assemblies (Can't include Newtonsoft JSON in CSharpCodeProvider script). With "Core" I don't get errors about a library, but it doesn't know the type, like it didn't get loaded.
I tried both using the project libraries (commented out) and specifying them directly, but have the same issue. To recreate, make a new .netCore 3.1 console application called "TestScript" and install nuget packages "Microsoft.CodeAnalysis.CSharp.Scripting" v 3.7.0, "Newtonsoft.Json" v12.0.3 and use the following code.
using System;
using System.IO;
using System.Linq;
using System.Collections.Generic;
using System.Reflection;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using System.Diagnostics;
using Newtonsoft.Json.Linq;
namespace TestScript
{
class Program
{
public static void Example1()
{
var assemblyName = "UserScript";
var code = @"namespace UserScript
{
using System;
using System.IO;
using System.Collections.Generic;
using Newtonsoft.Json.Linq;
public class RunScript
{
private const int x = 99;
public int Eval()
{
JObject j = new JObject();
return x;
}
}
}";
SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(code);
var references = new List<MetadataReference>();
//Load project libraries
//var assemblies = AppDomain.CurrentDomain
// .GetAssemblies()
// .Where(a => !a.IsDynamic)
// .Select(a => a.Location);
//foreach (var item in assemblies)
//{
// if (!item.Contains("xunit"))
// references.Add(MetadataReference.CreateFromFile(item));
//}
//or specify the libraries to load.
var coreDir = Directory.GetParent(typeof(Enumerable).GetTypeInfo().Assembly.Location);
var exeDir = Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName);
references.Add(MetadataReference.CreateFromFile(typeof(Object).GetTypeInfo().Assembly.Location));
references.Add(MetadataReference.CreateFromFile(typeof(Uri).GetTypeInfo().Assembly.Location));
references.Add(MetadataReference.CreateFromFile(coreDir.FullName + Path.DirectorySeparatorChar + "mscorlib.dll"));
references.Add(MetadataReference.CreateFromFile(coreDir.FullName + Path.DirectorySeparatorChar + "System.Runtime.dll"));
if (File.Exists(exeDir + "\\Newtonsoft.Json.dll"))
references.Add(MetadataReference.CreateFromFile(exeDir + "\\Newtonsoft.Json.dll"));
else
throw new Exception("Missing newtonsoft DLL");
CSharpCompilation compilation = CSharpCompilation.Create(
assemblyName,
new[] { syntaxTree },
new MetadataReference[]
{
MetadataReference.CreateFromFile(typeof(object).Assembly.Location)
},
new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
using (var memoryStream = new MemoryStream())
{
var result = compilation.Emit(memoryStream);
if (result.Success)
{
memoryStream.Seek(0, SeekOrigin.Begin);
Assembly assembly = Assembly.Load(memoryStream.ToArray());
Type testClassType = assembly.GetType("TestNamespace.TestClass");
var addResult = (int)testClassType.GetMethod("Add").Invoke(null, new object[] { 3, 4 });
Console.WriteLine(addResult);
}
else
{
Console.WriteLine("Failed to compile");
for (var i = 0; i < result.Diagnostics.Length; i++)
{
Console.WriteLine(result.Diagnostics[i].ToString());
}
}
}
}
static void Main(string[] args)
{
JObject j = null; //to make sure newtonsoft is included if loading current projects libraries
Example1();
}
}
}
Your code should work fine if you don't forget to use the
references
list you've built up.See test code on .NET Fiddle (link) - I used the
AppDomain
method there (one you commented out).Also, your invocations weren't actually calling the right Class and Method, which I guess you'll find out after you get past the compilation issues.
Edit: Here's the full working code in case the Fiddle gets deleted: