-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathCSharpCodeRunner.cs
More file actions
93 lines (82 loc) · 3.42 KB
/
CSharpCodeRunner.cs
File metadata and controls
93 lines (82 loc) · 3.42 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
using System;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.JavaScript;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using System.Net.Http;
using System.Threading.Tasks;
public partial class CSharpCodeRunner
{
static async Task<MetadataReference> LoadAssemblyFromServer(string assemblyName)
{
var baseUrl = GetHRef();
var url = $"/lib/{assemblyName}";
try
{
using var httpClient = new HttpClient { BaseAddress = new Uri(baseUrl) };
var assemblyBytes = await httpClient.GetByteArrayAsync(url);
Console.WriteLine($"Loaded {assemblyName} from server.");
return MetadataReference.CreateFromImage(assemblyBytes);
}
catch (Exception ex)
{
Console.WriteLine($"Error loading assembly {assemblyName}: {ex.Message}");
throw;
}
}
[JSExport]
internal static Task<string> CompileAndRun(string code)
{
return Task.Run(async () =>
{
try
{
var syntaxTree = CSharpSyntaxTree.ParseText(code);
// Use Task.WhenAll to run async LoadAssemblyFromServer in parallel
var references = await Task.WhenAll(
LoadAssemblyFromServer("mscorlib.dll"),
LoadAssemblyFromServer("netstandard.dll"),
LoadAssemblyFromServer("System.Console.dll"),
LoadAssemblyFromServer("System.Private.CoreLib.dll"),
LoadAssemblyFromServer("System.Runtime.dll"),
LoadAssemblyFromServer("System.Runtime.InteropServices.JavaScript.dll"),
LoadAssemblyFromServer("research.dll")
);
// Create a compilation with the syntax tree and references
var compilation = CSharpCompilation.Create(
assemblyName: "DynamicAssembly",
syntaxTrees: new[] { syntaxTree },
references: references,
options: new CSharpCompilationOptions(OutputKind.ConsoleApplication)
);
// Create a MemoryStream to store the compiled assembly
using var ms = new MemoryStream();
var emitResult = compilation.Emit(ms);
// Check for compilation errors
if (!emitResult.Success)
{
var errors = string.Join("\n", emitResult.Diagnostics.Where(d => d.Severity == DiagnosticSeverity.Error).Select(d => d.GetMessage()));
return $"Compilation failed:\n{errors}";
}
// Load the compiled assembly into the current AppDomain
ms.Seek(0, SeekOrigin.Begin);
var assembly = AppDomain.CurrentDomain.Load(ms.ToArray());
// Get the entry point and invoke it
var entryPoint = assembly.EntryPoint;
if (entryPoint != null)
{
var result = entryPoint.Invoke(null, null);
return result?.ToString() ?? "Execution complete, no output.";
}
return "No entry point found.";
}
catch (Exception ex)
{
return $"Error: {ex}";
}
});
}
[JSImport("window.location.href", "main.js")]
public static partial string GetHRef();
}