I implemented it like this:
public class RazorCompiler
{
private static readonly string _assemblyPath = Path.GetDirectoryName(typeof(object).Assembly.Location)!;
private static readonly MetadataReference[] _references =
[
MetadataReference.CreateFromFile(Assembly.GetExecutingAssembly().Location),
MetadataReference.CreateFromFile(typeof(object).Assembly.Location),
MetadataReference.CreateFromFile(typeof(IComponent).Assembly.Location),
MetadataReference.CreateFromFile(typeof(RazorCompiledItemAttribute).Assembly.Location),
MetadataReference.CreateFromFile(Path.Combine(_assemblyPath, "mscorlib.dll")),
MetadataReference.CreateFromFile(Path.Combine(_assemblyPath, "System.dll")),
MetadataReference.CreateFromFile(Path.Combine(_assemblyPath, "System.Core.dll")),
MetadataReference.CreateFromFile(Path.Combine(_assemblyPath, "System.Runtime.dll"))
];
private static readonly RazorProjectFileSystem _projectFilesystem = RazorProjectFileSystem.Create(".");
private static readonly RazorProjectEngine _engine = RazorProjectEngine.Create(RazorConfiguration.Default, _projectFilesystem);
private static readonly CSharpCompilationOptions _compilationOptions = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)
.WithOverflowChecks(true)
.WithOptimizationLevel(OptimizationLevel.Release);
public Assembly Compile(string sourceFile)
{
ArgumentException.ThrowIfNullOrEmpty(sourceFile);
var item = _projectFilesystem.GetItem(sourceFile);
var codeDocument = _engine.Process(item);
var csDocument = codeDocument.GetCSharpDocument();
var syntaxTree = CSharpSyntaxTree.ParseText(csDocument.GeneratedCode);
var assemblyName = Path.GetRandomFileName();
var compilation = CSharpCompilation.Create(assemblyName, [syntaxTree], _references, _compilationOptions);
using var assemblyStrean = new MemoryStream();
var result = compilation.Emit(assemblyStrean);
if (!result.Success)
{
throw new InvalidOperationException(string.Join(Environment.NewLine, result.Diagnostics.Where(x => x.Severity == DiagnosticSeverity.Error).Select(x => x.GetMessage())));
}
var assembly = Assembly.Load(assemblyStrean.ToArray());
return assembly;
}
}
And it works like a charm! I just need to pick up the first Type exposed from the returned Assembly, which will implement IComponent, and it's done.