I'm using Roslyn to compile my class in runtime to assembly output. I've added my needed assemblies into metadata references as below:
```c#
string p = Path.GetDirectoryName(typeof(object).Assembly.Location);
_ref = new MetadataReference[] {
MetadataReference.CreateFromFile(Path.Combine(p, "System.Collections.dll")),
MetadataReference.CreateFromFile(Path.Combine(p, "System.Runtime.dll")),
MetadataReference.CreateFromFile(Path.Combine(p, "System.Private.CoreLib.dll")),
MetadataReference.CreateFromFile(typeof(object).Assembly.Location),
MetadataReference.CreateFromFile(typeof(Schema).Assembly.Location)
};
And my CSharp syntax tree:
```c#
using System;
namespace _
{
public sealed class Model : Record
{
public string name;
public decimal amount;
public bool granted;
public DateTime birthdate;
}
}
And when I use my dll file in another project, I got an error when I create an instance of Model, the error is located on my decimal property which is amount. Omnisharp shows me:
The type 'Decimal' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e'.
As far as I known, the System.Private.CoreLib.dll has been existed in typeof(object).Assembly.Location, so it doesn't make any sense if still giving me the error.
What's wrong here??
@jaredpar can you please help me route this issue? It looks like Roslyn specific.
The problem here is that you shoudl never reference System.Private.Corelib directly. It's a runtime DLL, not a compile time one. It's in some cases designed specifically to not be referencable. You need to compile against the reference libraries, like netstandard, instead.
If I don't reference that DLL, I'd get an error that ask me to reference it because System.Decimal could not be found. What should I do?
What is the exact error and the full list of DLLs that are referenced? Should also include where you are referencing them from.
It's much trickier to do this on CoreCLR than Desktop. Have to be careful to reference the correct reference DLLs. Referencing the runtime ones, or mixing the two, will lead to a lot of issues.
I simplified the case. I have 2 netcore projects, The first one is where Roslyn generates my Model class (contains 'string', 'int', and 'decimal' properties) into a DLL file by using FileStream approach (not MemoryStream). The metadatareference[] assemblies linked are:
'System.Runtime
System.Private.CoreLib
and typeof(MyCurrentClass).Assembly.Location'
If I run this one, it works and produces the dll of MyCurrentClass completely.
Now I try to reference my those DLLs (MyCurrentClass.dll and MyFirstProject.dll) into the second project, I use itemgroup reference in my .csproj file. And I try to create a simple instance of MyCurrentClass, but I got an error when I try to access the 'decimal' property of it, the other properties work fine, only the 'decimal' one.
Now I try to reference my those DLLs (MyCurrentClass.dll and MyFirstProject.dll) into the second project,
Mentioned this in my first response though: don't reference System.Private.Corelib. It's not supported and if it works it's an accidental success.
But, it asks me to reference it by giving me an error if I don't reference it. I even add that reference because of the error.
It asks you to give that reference because you're providing other runtime libraries instead of reference libraries. As I mentioned in my earlier comment:
What is the exact error and the full list of DLLs that are referenced? Should also include where you are referencing them from.
The latter part will likely point to the runtime directory which is the source of the problem.
I put the latter part because I need to inherit a class from MyProject.dll, how can I achieve that?
@justinushermawan run HelloWorld compilation in VS. Enable verbose msbuild logs, check the args it passes to Roslyn - you will see it uses reference assemblies, none of which is called System.Private.Corelib.
Reference assemblies is where types live at compile time. At runtime many of those type-forward to implementation assemblies (like System.Private.Corelib).
You should never see an app or library to reference the implementation assembly - if they do, it is a bug they need to fix.
@karelz I've removed those implementation assemblies in my metadatareference, now I got the following errors on runtime:
Unhandled Exception: System.Exception: CS8021: No value for RuntimeMetadataVersion found. No assembly containing System.Object was found nor was a value for RuntimeMetadataVersion specified through options.
CS0246: The type or namespace name 'Record' could not be found (are you missing a using directive or an assembly reference?)
CS0518: Predefined type 'System.String' is not defined or imported
CS0518: Predefined type 'System.Int64' is not defined or imported
CS0518: Predefined type 'System.Void' is not defined or imported
CS0518: Predefined type 'System.Object' is not defined or imported
CS0518: Predefined type 'System.Int64' is not defined or imported
CS0518: Predefined type 'System.Object' is not defined or imported
CS0246: The type or namespace name 'Record' could not be found (are you missing a using directive or an assembly reference?)
CS0518: Predefined type 'System.Int64' is not defined or imported
CS0518: Predefined type 'System.String' is not defined or imported
CS0518: Predefined type 'System.Object' is not defined or imported
CS0246: The type or namespace name 'Record' could not be found (are you missing a using directive or an assembly reference?)
CS0115: 'Employee.Write(string, long)': no suitable method found to override
CS0115: 'Employee.Read(SortedList<long, Record>, out long, string)': no suitable method found to override
CS0518: Predefined type 'System.String' is not defined or imported
CS0518: Predefined type 'System.String' is not defined or imported
CS0518: Predefined type 'System.Decimal' is not defined or imported
CS0518: Predefined type 'System.Int32' is not defined or imported
CS0518: Predefined type 'System.Object' is not defined or imported
CS0246: The type or namespace name 'DateTime' could not be found (are you missing a using directive or an assembly reference?)
CS0518: Predefined type 'System.Object' is not defined or imported
CS0246: The type or namespace name 'BinaryWriter' could not be found (are you missing a using directive or an assembly reference?)
CS0518: Predefined type 'System.Object' is not defined or imported
CS0246: The type or namespace name 'BinaryWriter' could not be found (are you missing a using directive or an assembly reference?)
CS0518: Predefined type 'System.Object' is not defined or imported
CS0246: The type or namespace name 'FileStream' could not be found (are you missing a using directive or an assembly reference?)
CS0518: Predefined type 'System.String' is not defined or imported
CS0518: Predefined type 'System.Object' is not defined or imported
CS0518: Predefined type 'System.Int32' is not defined or imported
CS0518: Predefined type 'System.Object' is not defined or imported
CS0103: The name 'DateTime' does not exist in the current context
CS0518: Predefined type 'System.String' is not defined or imported
CS0518: Predefined type 'System.Object' is not defined or imported
CS0103: The name 'FileMode' does not exist in the current context
CS0518: Predefined type 'System.Object' is not defined or imported
CS0518: Predefined type 'System.Object' is not defined or imported
CS1061: 'Employee' does not contain a definition for 'next' and no accessible extension method 'next' accepting a first argument of type 'Employee' could be found (are you missing a using directive or an assembly reference?)
CS0518: Predefined type 'System.Object' is not defined or imported
CS0518: Predefined type 'System.Boolean' is not defined or imported
CS0518: Predefined type 'System.Boolean' is not defined or imported
CS0518: Predefined type 'System.Object' is not defined or imported
CS1061: 'Employee' does not contain a definition for 'id' and no accessible extension method 'id' accepting a first argument of type 'Employee' could be found (are you missing a using directive or an assembly reference?)
CS0518: Predefined type 'System.Object' is not defined or imported
CS1061: 'Employee' does not contain a definition for 'state' and no accessible extension method 'state' accepting a first argument of type 'Employee' could be found (are you missing a using directive or an assembly reference?)
CS0518: Predefined type 'System.Object' is not defined or imported
CS1061: 'Employee' does not contain a definition for 'timestamp' and no accessible extension method 'timestamp' accepting a first argument of type 'Employee' could be found (are you missing a using directive or an assembly reference?)
CS0518: Predefined type 'System.Object' is not defined or imported
CS1061: 'Employee' does not contain a definition for 'memento' and no accessible extension method 'memento' accepting a first argument of type 'Employee' could be found (are you missing a using directive or an assembly reference?)
CS0518: Predefined type 'System.Object' is not defined or imported
CS0518: Predefined type 'System.Object' is not defined or imported
CS0246: The type or namespace name 'BinaryReader' could not be found (are you missing a using directive or an assembly reference?)
CS0518: Predefined type 'System.Object' is not defined or imported
CS0246: The type or namespace name 'BinaryReader' could not be found (are you missing a using directive or an assembly reference?)
CS0518: Predefined type 'System.Object' is not defined or imported
CS0246: The type or namespace name 'FileStream' could not be found (are you missing a using directive or an assembly reference?)
CS0518: Predefined type 'System.Object' is not defined or imported
CS0103: The name 'FileMode' does not exist in the current context
CS0518: Predefined type 'System.Int64' is not defined or imported
CS0518: Predefined type 'System.Int32' is not defined or imported
CS0518: Predefined type 'System.Boolean' is not defined or imported
CS0518: Predefined type 'System.Boolean' is not defined or imported
CS0518: Predefined type 'System.Object' is not defined or imported
CS0518: Predefined type 'System.Object' is not defined or imported
CS0103: The name 'Activator' does not exist in the current context
CS0518: Predefined type 'System.Object' is not defined or imported
CS0518: Predefined type 'System.Type' is not defined or imported
CS0518: Predefined type 'System.Boolean' is not defined or imported
CS0518: Predefined type 'System.Object' is not defined or imported
CS0518: Predefined type 'System.Object' is not defined or imported
CS1061: 'Employee' does not contain a definition for 'next' and no accessible extension method 'next' accepting a first argument of type 'Employee' could be found (are you missing a using directive or an assembly reference?)
CS0518: Predefined type 'System.Object' is not defined or imported
CS1061: 'Employee' does not contain a definition for 'id' and no accessible extension method 'id' accepting a first argument of type 'Employee' could be found (are you missing a using directive or an assembly reference?)
CS0518: Predefined type 'System.Object' is not defined or imported
CS1061: 'Employee' does not contain a definition for 'state' and no accessible extension method 'state' accepting a first argument of type 'Employee' could be found (are you missing a using directive or an assembly reference?)
CS0518: Predefined type 'System.Object' is not defined or imported
CS1061: 'Employee' does not contain a definition for 'timestamp' and no accessible extension method 'timestamp' accepting a first argument of type 'Employee' could be found (are you missing a using directive or an assembly reference?)
CS0518: Predefined type 'System.Object' is not defined or imported
CS1061: 'Employee' does not contain a definition for 'memento' and no accessible extension method 'memento' accepting a first argument of type 'Employee' could be found (are you missing a using directive or an assembly reference?)
CS0518: Predefined type 'System.Object' is not defined or imported
CS0246: The type or namespace name 'DateTime' could not be found (are you missing a using directive or an assembly reference?)
CS0518: Predefined type 'System.Object' is not defined or imported
CS1061: 'Employee' does not contain a definition for 'memento' and no accessible extension method 'memento' accepting a first argument of type 'Employee' could be found (are you missing a using directive or an assembly reference?)
CS0518: Predefined type 'System.Object' is not defined or imported
CS0103: The name 'Memento' does not exist in the current context
CS0518: Predefined type 'System.Boolean' is not defined or imported
CS0518: Predefined type 'System.Boolean' is not defined or imported
CS0518: Predefined type 'System.Object' is not defined or imported
Note that the Record class is located in my parent project.
How to handle it?
Is that HelloWorld app? Did you try to mimic what VS does with the references?
Yes, I tried with 2 simple projects, the one that produced the DLL of simple class, and the second one that using the DLL, it still doesn't work.
ok, can you share full repro for the HelloWorld-style repro?
This is wrong:
https://github.com/justinushermawan/roslyn-test/blob/master/Core/Program.cs#L28
You're using implementation DLL (the one you're running on), not reference assemblies as you should.
What should I change it with? I tried netstandard.dll, still not working.
I don't know from top of my head - as I suggested above https://github.com/dotnet/core/issues/2082#issuecomment-442657113, you can check what VS does and where the reference assemblies directory is.
These one?

It works when I use:
string p = @"C:\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.netcore.app\2.1.0\ref\netcoreapp2.1\";
MetadataReference[] _ref = new MetadataReference[] {
MetadataReference.CreateFromFile(Path.Combine(p, "netstandard.dll")),
MetadataReference.CreateFromFile(Path.Combine(p, "System.dll")),
MetadataReference.CreateFromFile(Path.Combine(p, "System.Runtime.dll"))
};
Is it the right way?
I believe the "absolutely right" way would be to make use of compilation context preservation.
<PropertyGroup>
<PreserveCompilationContext>true</PreserveCompilationContext>
</PropertyGroup>
Microsoft.Extensions.DependencyModel: <ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyModel" Version="2.1.0" />
</ItemGroup>
DependencyContext to get compilation references:using Microsoft.Extensions.DependencyModel;
using System.Linq;
…
MetadataReference[] _ref =
DependencyContext.Default.CompileLibraries
.SelectMany(cl => cl.ResolveReferencePaths())
.Select(asm => MetadataReference.CreateFromFile(asm))
.ToArray();
If you absolutely only want the .NET Core references, and not all the referencest that your app has, you can use
MetadataReference[] _ref =
DependencyContext.Default.CompileLibraries
.First(cl => cl.Name == "Microsoft.NETCore.App")
.ResolveReferencePaths()
.Select(asm => MetadataReference.CreateFromFile(asm))
.ToArray();
Note that on publish, this will create a refs\ subfolder containing compile-time reference DLLs.
@dasMulli Yeah, it works. Thank you.
Would you please explain my code mistakes?
Would you please explain my code mistakes?
Not a mistake, there's just an awful lot of things that can go wrong and you'd need detailed information about how either compilation or the layering of runtime DLLs work.
PreserveCompilationContext makes sure that your .deps.json contains the references that your app has during compilation. When you build your app, the compile-time assemblies come from the Microsoft.NETCore.App NuGet package. Specifically, from
.nuget/packages/microsoft.netcore.app/2.1.0/ref/netcoreapp2.1/*.dll
There also is a set of MSBuild targets that resolves conflicts of NuGet packages that contain implementations for older versions of .NET Core that are now part of .NET Core (specifically, the System.* NuGet packages from the 1.* timeframe).
The preserved compilation context will also contain the filtered results so you're not going to run into conflicts.
DependencyContext will help you read the .deps.json at runtime and resolve the paths to the dll files you need.
Does PreserveCompilationContext make my build time slower? And if I don't set it to true, can't DependencyContext work?
Does PreserveCompilationContext make my build time slower?
May be a bit, but it shouldn't matter.
And if I don't set it to true, can't DependencyContext work?
Nope, it will throw exceptions. And you'll be missing the dlls once published.
Oh I see. Thanks in advance for your help.
Thanks ! @dasMulli
@dasMulli are you absolutely sure this is the only way to properly compile C# with Roslyn? I can't believe these reference assemblies can only be accessed with a project setting and an external NuGet dependency. This means Roslyn is completely incapable of compiling even the simplest program on its own. What good is it then?
Most helpful comment
I believe the "absolutely right" way would be to make use of compilation context preservation.
Microsoft.Extensions.DependencyModel:DependencyContextto get compilation references:If you absolutely only want the .NET Core references, and not all the referencest that your app has, you can use
Note that on publish, this will create a
refs\subfolder containing compile-time reference DLLs.