Roslyn has no reference to System.Runtime
Asked Answered
N

3

32

I'm working on a project where we are using Roslyn to compile some templates for us. Now when I'm compiling the template I'm receiving multiple errors in the CompileResult.Diagnostics.

The errors are:

(21,6): error CS0012: The type 'System.Attribute' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'.
(21,6): error CS0012: The type 'System.Type' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'.

Seeing these errors I assumed I didn't add a reference to the System.Runtime assembly correctly. However, after checking the loaded assemblies this appears to be in order.

private IEnumerable<MetadataReference> GetGlobalReferences()
{
    var assemblies = new [] 
        {
            typeof(System.Object).Assembly,                         //mscorlib
            typeof(System.Composition.ExportAttribute).Assembly,    //System.Composition (MEF)
            typeof(System.CodeDom.Compiler.CodeCompiler).Assembly,  //System.CodeDom.Compiler
        };

    var refs = from a in assemblies
                select new MetadataFileReference(a.Location);

    return refs.ToList();
}

And the compilation itself:

public void Compile(AssemblyFileInfo assemblyInfo)
{
    Parse(assemblyInfo.Files);

    var compilation = CSharpCompilation.Create(assemblyInfo.FilePath, options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary))
                        .AddReferences(GetGlobalReferences())
                        .AddSyntaxTrees(assemblyInfo.SourceCodeSyntaxTrees);

    assemblyInfo.CompileResult = compilation.Emit(assemblyInfo.FilePath);
}

Am I missing something obvious? It looks like all the prerequisites for a successfull compilation are satisfied, but apparently they aren't.

For reference, this is the (obfuscated) piece of code I'm trying to compile:

namespace Project.Rules.Generated
{
    using System;
    using System.Runtime;
    using System.Composition;
    using System.CodeDom.Compiler;

    [Export(typeof(IProject))]
    [GeneratedCode("Project Template Compiler", "1.0")]
    public sealed class ProcessPriorityValue : ProjectConcreteClass
    {
        public override void Execute(ProjectExecutionContext ctx)
        {
            CurrentContext = ctx;
        }
    }
}

edit I've advanced in my searchings a bit. The PublicKeyToken specified in the error messages match the PublicKeyToken of the System.Composition assemblies. My guess was adding all of the assemblies could possibly fix the issue. This is correct, or at least part of the solution. By using dotPeek I was able to check which objects exist in the different assemblies. With this knowledge I've changed the GetGlobalReferences() method to this:

private IEnumerable<MetadataReference> GetGlobalReferences()
{
    var assemblies = new [] 
        {
            typeof(System.Object).Assembly,                                     //mscorlib
            typeof(System.Composition.ExportAttribute).Assembly,                //System.Composition.AttributeModel
            typeof(System.Composition.Convention.ConventionBuilder).Assembly,   //System.Composition.Convention
            typeof(System.Composition.Hosting.CompositionHost).Assembly,        //System.Composition.Hosting
            typeof(System.Composition.CompositionContext).Assembly,             //System.Composition.Runtime
            typeof(System.Composition.CompositionContextExtensions).Assembly,   //System.Composition.TypedParts
            typeof(System.CodeDom.Compiler.CodeCompiler).Assembly,              //System.CodeDom.Compiler
        };

    var refs = from a in assemblies
                select new MetadataFileReference(a.Location);

    return refs.ToList();
}

As you can see, I'm adding all System.Composition assemblies now by specifying an object which exists in the assembly. By adding the System.Composition.Runtime, my compile errors were solve.

This did introduce a different error though. As you can check out yourself, there is a generic Export class in System.Composition.Runtime: public sealed class Export<T> : IDisposable Because of this I'm now getting this error:

(21,6): error CS0404: Cannot apply attribute class 'System.Composition.Export<T>' because it is generic

For some reason the code now wants to use System.Composition.Runtime.Export<T> and not the ExportAttribute, defined in System.Composition.AttributeModel assembly.

edit2

I can confirm the above code uses the System.Composition.Export<T> and not the ExportAttribute. I discovered this by changing the [Export(typeof(IProject)] to [ExportAttribute(typeof(IProject)]. Because of this change, the original errors returned. It looks like the assembly System.Composition.AttributeModel isn't loaded/referenced correctly, but after checking the compilation, I can see the assembly is referenced ok.

Referenced assemblies I've got at the moment are:

+       [0] mscorlib, Version=4.0.0.0, Culture=neutral, PublicKey=00000000000000000400000000000000  Microsoft.CodeAnalysis.AssemblyIdentity
+       [1] System.Composition.AttributedModel, Version=1.0.20.0, Culture=neutral, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293   Microsoft.CodeAnalysis.AssemblyIdentity
+       [2] System.Composition.Convention, Version=1.0.20.0, Culture=neutral, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293    Microsoft.CodeAnalysis.AssemblyIdentity
+       [3] System.Composition.Hosting, Version=1.0.20.0, Culture=neutral, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293   Microsoft.CodeAnalysis.AssemblyIdentity
+       [4] System.Composition.Runtime, Version=1.0.20.0, Culture=neutral, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293   Microsoft.CodeAnalysis.AssemblyIdentity
+       [5] System.Composition.TypedParts, Version=1.0.20.0, Culture=neutral, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293    Microsoft.CodeAnalysis.AssemblyIdentity
+       [6] Microsoft.CSharp, Version=4.0.0.0, Culture=neutral, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293  Microsoft.CodeAnalysis.AssemblyIdentity
+       [7] System, Version=4.0.0.0, Culture=neutral, PublicKey=00000000000000000400000000000000    Microsoft.CodeAnalysis.AssemblyIdentity
+       [8] System.Core, Version=4.0.0.0, Culture=neutral, PublicKey=00000000000000000400000000000000   Microsoft.CodeAnalysis.AssemblyIdentity
+       [9] System.Data, Version=4.0.0.0, Culture=neutral, PublicKey=00000000000000000400000000000000   Microsoft.CodeAnalysis.AssemblyIdentity
Nickolasnickolaus answered 28/5, 2014 at 9:8 Comment(5)
Your comments may be misleading. So far as I can see, System.Runtime.ProfileOptimization is in mscorlib, not the System.Runtime assembly.Bregma
You are correct, I just figured this out myself also. It appears there isn't a System.Runtime assembly, everything should be available in the mcorslib. Just deleted the line from the post and the source, so it's a bit cleaner.Nickolasnickolaus
This sounds like when using the /nostdlib option for csc.Unopened
Your answer just helped to resolve my issue. Thanks! Don't you want to post it as an real answer instead of an answer as part of the question? I almost overlooked it... P.S. congratulations on your 2226 SO points ;)Priestley
Good point! I'll post it as a separate answer.Nickolasnickolaus
N
25

By request of Dejan in the comment section, I'll post the answer (to my problem) as a real answer.


I've found out what the problem was! The compiler was correct all along. A blog post of smack0007 triggered me of trying something else. Instead of using the Facade dll, try referencing the necessary dll's manually. The GetGlobalReferences method now looks like this:

private IEnumerable<MetadataReference> GetGlobalReferences()
{
    var assemblies = new [] 
        {
            /*Making sure all MEF assemblies are loaded*/
            typeof(System.Composition.Convention.AttributedModelProvider).Assembly, //System.Composition.AttributeModel
            typeof(System.Composition.Convention.ConventionBuilder).Assembly,   //System.Composition.Convention
            typeof(System.Composition.Hosting.CompositionHost).Assembly,        //System.Composition.Hosting
            typeof(System.Composition.CompositionContext).Assembly,             //System.Composition.Runtime
            typeof(System.Composition.CompositionContextExtensions).Assembly,   //System.Composition.TypedParts

            /*Used for the GeneratedCode attribute*/
            typeof(System.CodeDom.Compiler.CodeCompiler).Assembly,              //System.CodeDom.Compiler
        };

    var refs = from a in assemblies 
                select new MetadataFileReference(a.Location);
    var returnList = refs.ToList();

    //The location of the .NET assemblies
    var assemblyPath = Path.GetDirectoryName(typeof(object).Assembly.Location);

    /* 
        * Adding some necessary .NET assemblies
        * These assemblies couldn't be loaded correctly via the same construction as above,
        * in specific the System.Runtime.
        */
    returnList.Add(new MetadataFileReference(Path.Combine(assemblyPath, "mscorlib.dll")));
    returnList.Add(new MetadataFileReference(Path.Combine(assemblyPath, "System.dll")));
    returnList.Add(new MetadataFileReference(Path.Combine(assemblyPath, "System.Core.dll")));
    returnList.Add(new MetadataFileReference(Path.Combine(assemblyPath, "System.Runtime.dll")));

    return returnList;
}

When decompiling the System.Runtime.dll I also saw why it couldn't be referenced in any other way. The dll is empty, it only contains some references to other assemblies. Therefore one can't reference this assembly in any other way.

Nickolasnickolaus answered 9/11, 2017 at 7:47 Comment(2)
Started googling and found the answer with a link to my own blog post...Bulbar
FYI, MetadataFileReference has been changed to MetadataReference instead, so it should be MetadataReference.CreateFromFile(Path.Combine(assemblyPath, "System.Runtime.dll"))Grandmother
I
11

It appears that you are referencing a PortableClassLibrary. Portable Class Libraries pick up some of the basic types (like object/string/etc) from "System.Runtime.dll". However, in the desktop framework these come from mscorlib.dll. When you use typeof(object).Assembly, you get Roslyn's own version of object. Since Roslyn is not built as Portable Class Libraries, that is the one from mscorlib, and doesn't match the identity of your other references.

Impaction answered 28/5, 2014 at 16:15 Comment(3)
This answer sounds valid. How can you see I'm referencing a PCL, is it the publickkey from the referenced mscorlib? I'm asking, because I'm not referencing any PCL's (on purpose) in my application. I really want to reference the actual desktop/IIS version of mscorlib. I found out that when adding the System.Runtime facade dll (#12349689), Roslyn actually compiles my code. Too bad the assembly binding redirect from that post doesn't appear to work as that's a bit cleaner.Nickolasnickolaus
I've checked the path to the referenced mscorlib.dll and it's C:\\Windows\\Microsoft.NET\\Framework\\v4.0.30319\\mscorlib.dll, which looks like the 'real' .NET 4 assemblyNickolasnickolaus
I guessed it from the fact that you needed System.Runtime.dll. Binding redirects won't work because (1) they only work to redirect to different versions of the same assembly, and (2) they control runtime behavior, not compiler behavior. You can see which of the other references you are adding requires System.Runtime by looking at their extern sections in ildasm.exeImpaction
G
7

The predefined list of references was not working for me.

But getting them from the AppDomain helped:

public static readonly List<PortableExecutableReference> References = 
    AppDomain.CurrentDomain.GetAssemblies()
        .Where(_ => !_.IsDynamic && !string.IsNullOrWhiteSpace(_.Location))
        .Select(_ => MetadataReference.CreateFromFile(_.Location))
        .Concat(new[]
        {
            // add your app/lib specifics, e.g.:                      
            MetadataReference.CreateFromFile(typeof(MyType).Assembly.Location),
        })
        .ToList();

I found the answer in this helpful repo: https://github.com/andrewlock/NetEscapades.EnumGenerators

Gloriole answered 14/6, 2022 at 14:41 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.