Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
395 views
in Technique[技术] by (71.8m points)

c# - Roslyn has no reference to System.Runtime

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
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...