The Pax Bisonica
The Pax Bisonica

Reputation: 2164

c# getting Internal error in the expression evaluator when programmatically compiling code with Roslyn

I've set up a console project that compiles code on build based on a few really simple templates I have. The templates just setup classes that inherit from base classes in another project. I'm able to run the code and step through the base classes line by line, but when I try to see what the value of a property is I get Internal error in the expression evaluator. I've tried to set up the console project to compile everything with debug configurations:

CSharpCompilationOptions DefaultCompilationOptions =
    new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)
        .WithOverflowChecks(true)
        .WithOptimizationLevel(OptimizationLevel.Debug)
        .WithOutputKind(OutputKind.DynamicallyLinkedLibrary)
        .WithAssemblyIdentityComparer(DesktopAssemblyIdentityComparer.Default);

CSharpCompilation compilation = CSharpCompilation.Create(
    name,
    syntaxTrees: syntaxTrees,
    references: GetMetaDataReferences(context, moduleBinPath),
    options: DefaultCompilationOptions);

try
{
    var ms = new MemoryStream();
    var pdbStream = new MemoryStream();
    var docStream = new MemoryStream();

    var result = compilation.Emit(ms, pdbStream, docStream);
    if (!result.Success)
    {
        IEnumerable<Diagnostic> failures = result.Diagnostics.Where(diagnostic =>
            diagnostic.IsWarningAsError ||
            diagnostic.Severity == DiagnosticSeverity.Error);

        foreach (Diagnostic diagnostic in failures)
        {
            Console.Error.WriteLine("{0}: {1}", diagnostic.Id, diagnostic.GetMessage());
        }
    }
    else
    {
        CreateFile($"{moduleBinPath}\\{name}.dll", ms);
        CreateFile($"{moduleBinPath}\\{name}.pdb", pdbStream);
        CreateFile($"{moduleBinPath}\\{name}.xml", docStream);
    }

    ms.Dispose();
    pdbStream.Dispose();
    docStream.Dispose();
}
catch (Exception ex)
{
    Console.Error.WriteLine("Could not compile assembly!!");
    Console.Error.WriteLine(ex.ToString());
}

I then load the dll at startup:

string scriptPath = $"{moduleBinPath}\\{moduleAssembly}.Scripts.dll";
if (File.Exists(scriptPath))
{
    Assembly.LoadFile(scriptPath)
    AssemblyLoadContext.Default.Resolving += (loadContext, name) =>
    {
        if (!name.Name.Equals($"{moduleAssembly}.Scripts")) return null;
        return loadContext.LoadFromAssemblyPath(scriptPath);
    };
}

I can see that the symbols are loaded in the Modules window as well. Is there anything else I need to do to get debugging working properly?

Upvotes: 0

Views: 514

Answers (1)

The Pax Bisonica
The Pax Bisonica

Reputation: 2164

I actually ended up figuring this out, the biggest issue was with the fact that I was using Assembly.LoadFile instead of AssemblyLoadContext.Default.LoadFromAssemblyPath. The latter is much better at loading dependent assemblies of the plugin.

After doing a bit more research I stumbled upon this article that goes on to talk about how unreliable Assembly.LoadFile is. Its difficult to tell what exactly the issue was, but I'm assuming that there might have been some assembly version mismatches causing the expression evaluator to not work properly.

Upvotes: 1

Related Questions