Compiling and running code at runtime in .Net Core 1.0

Is it possible to compile and run C # code at runtime in a new .Net Core (better than the .NET Standard Platform)? I saw several examples (.Net Framework), but they used NuGet packages that are not compatible with netcoreapp1.0 (.NETCoreApp, Version = v1.0)

+12
c # .net-core .net-core-rc2
source share
3 answers

Option number 1 . Use the full C # compiler to compile the assembly, load, and then execute the method from it.

Your project.json project requires the following packages as dependencies:

"Microsoft.CodeAnalysis.CSharp": "1.3.0-beta1-20160429-01", "System.Runtime.Loader": "4.0.0-rc2-24027", 

Then you can use this code:

 var compilation = CSharpCompilation.Create("a") .WithOptions(new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)) .AddReferences( MetadataReference.CreateFromFile(typeof(object).GetTypeInfo().Assembly.Location)) .AddSyntaxTrees(CSharpSyntaxTree.ParseText( @" using System; public static class C { public static void M() { Console.WriteLine(""Hello Roslyn.""); } }")); var fileName = "a.dll"; compilation.Emit(fileName); var a = AssemblyLoadContext.Default.LoadFromAssemblyPath(Path.GetFullPath(fileName)); a.GetType("C").GetMethod("M").Invoke(null, null); 

Option number 2 . Use Roslyn scripts. This will greatly simplify the code, but more settings are currently required:

  • Create NuGet.config to receive packages from Roslyn night feed:

     <?xml version="1.0" encoding="utf-8"?> <configuration> <packageSources> <add key="Roslyn Nightly" value="https://www.myget.org/F/roslyn-nightly/api/v3/index.json" /> </packageSources> </configuration> 
  • Add the following package as a dependency on project.json (note that this is a package from today, you will need a different version in the future):

     "Microsoft.CodeAnalysis.CSharp.Scripting": "1.3.0-beta1-20160530-01", 

    You also need to import dotnet (the obsolete "Target Structure Monitor" that is still used by Roslyn ):

     "frameworks": { "netcoreapp1.0": { "imports": "dotnet5.6" } } 
  • Now you can finally use Scripting:

     CSharpScript.EvaluateAsync(@"using System;Console.WriteLine(""Hello Roslyn."");").Wait(); 
+20
source share

Just adding @svick in response to one answer. If you want to save the assembly in memory (instead of writing to a file), you can use the following method:

 AssemblyLoadContext context = AssemblyLoadContext.Default; Assembly assembly = context.LoadFromStream(ms); 

This is different than in Net451, where the code is located:

 Assembly assembly = Assembly.Load(ms.ToArray()); 

My code is for both Net451 and Netstandard, so I had to use directives to get around this problem. An example of the complete code is given below:

  string code = CreateFunctionCode(); var syntaxTree = CSharpSyntaxTree.ParseText(code); MetadataReference[] references = new MetadataReference[] { MetadataReference.CreateFromFile(typeof(object).GetTypeInfo().Assembly.Location), MetadataReference.CreateFromFile(typeof(Hashtable).GetTypeInfo().Assembly.Location) }; var compilation = CSharpCompilation.Create("Function.dll", syntaxTrees: new[] { syntaxTree }, references: references, options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); StringBuilder message = new StringBuilder(); using (var ms = new MemoryStream()) { EmitResult result = compilation.Emit(ms); if (!result.Success) { IEnumerable<Diagnostic> failures = result.Diagnostics.Where(diagnostic => diagnostic.IsWarningAsError || diagnostic.Severity == DiagnosticSeverity.Error); foreach (Diagnostic diagnostic in failures) { message.AppendFormat("{0}: {1}", diagnostic.Id, diagnostic.GetMessage()); } return new ReturnValue<MethodInfo>(false, "The following compile errors were encountered: " + message.ToString(), null); } else { ms.Seek(0, SeekOrigin.Begin); #if NET451 Assembly assembly = Assembly.Load(ms.ToArray()); #else AssemblyLoadContext context = AssemblyLoadContext.Default; Assembly assembly = context.LoadFromStream(ms); #endif Type mappingFunction = assembly.GetType("Program"); _functionMethod = mappingFunction.GetMethod("CustomFunction"); _resetMethod = mappingFunction.GetMethod("Reset"); } } 
+9
source share

Both of the previous answers did not help me in the .NET Core 2.2 environment on Windows. Need additional links.

So, with the help of https://stackoverflow.com/a/167155/ ... of the solution, I got the following code:

 var dotnetCoreDirectory = System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory(); var compilation = CSharpCompilation.Create("LibraryName") .WithOptions(new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)) .AddReferences( MetadataReference.CreateFromFile(typeof(object).GetTypeInfo().Assembly.Location), MetadataReference.CreateFromFile(typeof(Console).GetTypeInfo().Assembly.Location), MetadataReference.CreateFromFile(Path.Combine(dotnetCoreDirectory, "mscorlib.dll")), MetadataReference.CreateFromFile(Path.Combine(dotnetCoreDirectory, "netstandard.dll")), MetadataReference.CreateFromFile(Path.Combine(dotnetCoreDirectory, "System.Runtime.dll"))) .AddSyntaxTrees(CSharpSyntaxTree.ParseText( @"public static class ClassName { public static void MethodName() => System.Console.WriteLine(""Hello C# Compilation.""); }")); // Debug output. In case your environment is different it may show some messages. foreach (var compilerMessage in compilation.GetDiagnostics()) Console.WriteLine(compilerMessage); 

How to output the library to a file:

 var fileName = "LibraryName.dll"; var emitResult = compilation.Emit(fileName); if (emitResult.Success) { var assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(Path.GetFullPath(fileName)); assembly.GetType("ClassName").GetMethod("MethodName").Invoke(null, null); } 

or to the memory stream:

 using (var memoryStream = new MemoryStream()) { var emitResult = compilation.Emit(memoryStream); if (emitResult.Success) { memoryStream.Seek(0, SeekOrigin.Begin); var context = AssemblyLoadContext.Default; var assembly = context.LoadFromStream(memoryStream); assembly.GetType("ClassName").GetMethod("MethodName").Invoke(null, null); } } 
+2
source share

All Articles