Timothy Stepanski
Timothy Stepanski

Reputation: 1196

Receiving "You must add a reference to assembly 'netstandard'" Errors during Runtime Compilation

Using C# runtime compilation (Roslyn), I am receiving many errors stating I have not added references to netstandard despite compiling under the context of a netcoreapp.

Errors appear with the following format:

The type 'XXX' is defined in an assembly that is not referenced. You must add a reference to assembly 'netstandard, Version=2.0.0.0...

The code processing resulting in this can be distilled into the following snippet:

using System;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;

namespace Compiler
{
    public static class Compiler
    {
        public static Assembly CompileAssembly(string code, bool compileAsExecutable = false)
        {
            var outputKind = compileAsExecutable ? OutputKind.ConsoleApplication : OutputKind.DynamicallyLinkedLibrary;
            var syntaxTree = CSharpSyntaxTree.ParseText(code);
            var syntaxTrees = new[] {syntaxTree};
            var systemAssemblyReference = GetMetadataReference<object>();
            var patchBandAssemblyReference = GetMetadataReference<AssemblyTargetedPatchBandAttribute>();
            var references = new[] {systemAssemblyReference, patchBandAssemblyReference};
            var cSharpCompilationOptions = new CSharpCompilationOptions(outputKind);
            var compilation = CSharpCompilation.Create(@"Countdown", syntaxTrees, references, cSharpCompilationOptions);

            using (var assemblyStream = new MemoryStream())
            {
                var emitResult = compilation.Emit(assemblyStream);

                if (emitResult.Success)
                {
                    var assemblyBytes = assemblyStream.ToArray();

                    return Assembly.Load(assemblyBytes);
                }

                var errors = emitResult
                    .Diagnostics
                    .Select(diagnostic => diagnostic.GetMessage())
                    .Select(message => new Exception(message));

                throw new AggregateException(errors);
            }
        }

        private static string GetAssemblyLocation<T>()
        {
            var typeOfT = typeof(T);

            return typeOfT.Assembly.Location;
        }

        private static PortableExecutableReference GetMetadataReference<T>()
        {
            var assemblyLocation = GetAssemblyLocation<T>();

            return MetadataReference.CreateFromFile(assemblyLocation);
        }
    }
}

Upvotes: 1

Views: 1072

Answers (1)

Timothy Stepanski
Timothy Stepanski

Reputation: 1196

The solution was to add a reference to the netstandard.dll:

using System;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;

namespace Compiler
{
    public static class Compiler
    {
        public static Assembly CompileAssembly(string code, bool compileAsExecutable = false)
        {
            var outputKind = compileAsExecutable ? OutputKind.ConsoleApplication : OutputKind.DynamicallyLinkedLibrary;
            var syntaxTree = CSharpSyntaxTree.ParseText(code);
            var syntaxTrees = new[] {syntaxTree};

            // Requested the reference be fetched
            var runtimeSpecificReference = GetRuntimeSpecificReference();
            var systemAssemblyReference = GetMetadataReference<object>();
            var patchBandAssemblyReference = GetMetadataReference<AssemblyTargetedPatchBandAttribute>();

            // Added the reference to the value here
            var references = new[] {runtimeSpecificReference, systemAssemblyReference, patchBandAssemblyReference};

            var cSharpCompilationOptions = new CSharpCompilationOptions(outputKind);
            var compilation = CSharpCompilation.Create(@"Countdown", syntaxTrees, references, cSharpCompilationOptions);

            using (var assemblyStream = new MemoryStream())
            {
                var emitResult = compilation.Emit(assemblyStream);

                if (emitResult.Success)
                {
                    var assemblyBytes = assemblyStream.ToArray();

                    return Assembly.Load(assemblyBytes);
                }

                var errors = emitResult
                    .Diagnostics
                    .Select(diagnostic => diagnostic.GetMessage())
                    .Select(message => new Exception(message));

                throw new AggregateException(errors);
            }
        }

        private static string GetAssemblyLocation<T>()
        {
            var typeOfT = typeof(T);

            return typeOfT.Assembly.Location;
        }

        private static PortableExecutableReference GetMetadataReference<T>()
        {
            var assemblyLocation = GetAssemblyLocation<T>();

            return MetadataReference.CreateFromFile(assemblyLocation);
        }

        // This function was needed
        private static PortableExecutableReference GetRuntimeSpecificReference()
        {
            var assemblyLocation = GetAssemblyLocation<object>();
            var runtimeDirectory = Path.GetDirectoryName(assemblyLocation);
            var libraryPath = Path.Join(runtimeDirectory, @"netstandard.dll");

            return MetadataReference.CreateFromFile(libraryPath);
        }
    }
}

Upvotes: 1

Related Questions