I don't think Steve has released the Blazor spreadsheet demo yet, but I had a play myself, and if anyone wants to quickly try this, just start with the default Blazor Server template (.NET 7) then make these changes:
Here is the code for the above CompilerService service using Roslyn:
using DotNetIsolator;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Emit;
using Microsoft.CodeAnalysis.Text;
public class CompilerService
{
static CSharpCompilationOptions options = new(OutputKind.DynamicallyLinkedLibrary, optimizationLevel: Microsoft.CodeAnalysis.OptimizationLevel.Release);
static List<PortableExecutableReference> references = AppDomain.CurrentDomain.GetAssemblies()
.Where(asm => !asm.IsDynamic && !string.IsNullOrEmpty(asm.Location))
.Select(asm => MetadataReference.CreateFromFile(asm.Location))
//.Concat(new[] {MetadataReference.CreateFromFile(Assembly.Load(new AssemblyName("Microsoft.CSharp")).Location) }) // Dynamic support
.ToList();
// We will put generated assemblies here
static Dictionary<string, byte[]> assemblies = new();
static IsolatedRuntimeHost host = new IsolatedRuntimeHost()
.WithBinDirectoryAssemblyLoader()
.WithAssemblyLoader(name => assemblies.ContainsKey(name) ? assemblies[name] : null);
public string CompileAndRun(string code)
{
var parsedCode = CSharpSyntaxTree.ParseText(SourceText.From($$"""
using System;
using System.IO;
using System.Linq;
using System.Text.Json;
using System.Collections.Generic;
using static System.Console;
using static System.Math;
using static System.Text.Json.JsonSerializer;
public class MyLib
{
public static string RunCode()
{
var writer = new StringWriter();
Console.SetOut(writer);
Console.SetError(writer);
{{code}}
Console.Out.Flush();
return writer.ToString();
}
}
"""));
var assemblyName = Guid.NewGuid().ToString();
using var templateAssemblyStream = new MemoryStream();
using var templatePdbStream = new MemoryStream();
var compilation = CSharpCompilation.Create(assemblyName, new SyntaxTree[] { parsedCode }, references, options);
var compilationResult = compilation.Emit(templateAssemblyStream, templatePdbStream, options: new(debugInformationFormat: DebugInformationFormat.Pdb));
if (!compilationResult.Success)
{
return string.Join("\n", compilationResult.Diagnostics.Select(i => i.ToString()));
}
else
{
assemblies.Add(assemblyName, templateAssemblyStream.ToArray());
}
var runtime = new IsolatedRuntime(host);
// Now we will invoke the method
var method = runtime.GetMethod(assemblyName, null, null, "MyLib", "RunCode");
return method.Invoke<string>(null);
}
}
Then in the Blazor Server app's Index.razor file, replace content with this code:
I'll mark the issue as closed since it's not tracking any pending work, but you can continue to link people here and people are welcome to continue discussing this below.
Steve, this is so exciting, thank you so much!
I don't think Steve has released the Blazor spreadsheet demo yet, but I had a play myself, and if anyone wants to quickly try this, just start with the default Blazor Server template (.NET 7) then make these changes:
Add these nuget packages in csproj:
In Program.cs register the following service:
Here is the code for the above CompilerService service using Roslyn:
Then in the Blazor Server app's Index.razor file, replace content with this code:
Now you can type code like this:
It recompiles with every keystroke. Note I am currently caching the old assemblies generated in a list, so this is just a demo, but lots of fun!