Roslyn: error CS0518: Predefined type 'System.Object' is not defined or imported

Created on 8 Jul 2016  ·  33Comments  ·  Source: dotnet/roslyn

Version Used:
Both:

  • Visual-Studio-2015-Update-3
  • commit b495d2161c48e99a51229238e09bdbb1d0baac41

OS:

  • Distributor ID: Ubuntu
  • Description: Ubuntu 14.04.3 LTS
  • Release: 14.04
  • Codename: trusty

Steps to Reproduce:

  1. Clone roslyn repo. Checkout one of the above versions. Run "make".
  2. Attempt to compile a trivial C# source file, e.g. one generated by "dotnet new": "Binaries/Debug/csccore/csc Program.cs"

Expected Behavior:
The program compiles.

Actual Behavior:
Error CS0518 is generated.

I figured out that mscorlib.dll in that directory only has forwarded types. I compiled coreclr and found the same thing there too... Referencing "System.Private.Corelib.dll" solves the issue (used ILSpy to figure out that's the assembly mscorlib.dll was referencing and just guessed). Referencing mscorlib.dll does NOT solve the issue (as one might expect).

My use-case for this workflow is to be able to package a C# compiler so that it's self-contained (does not rely on the system or any setup / downloading / caching). Is there another preferred way to do this instead?

Area-Interactive Concept-Portability Question

Most helpful comment

I think there is a lot of confusion around referencing .NET Core libraries. Runtime code generation using Roslyn compilations in .NET Core App clarifies.

It would definitely be desirable to make it simpler to avoid above issues.

All 33 comments

@agocke @jaredpar Can you please help answer this?

This is a bit tricky. Fundamentally, the compiler is not concerned with providing supporting assemblies like mscorlib/System.Runtime -- that's the job of the framework. CoreFX has decided to build an implementation for the framework where they split the compile surface area and the runtime surface area across different DLLs. This is why NuGet packages contain separate ref and lib folders.

All of this is to say: you're in a bit of a bind. CoreFX will expect that you compile against their ref assemblies (as provided by NuGet) and run against their implementation assemblies (as provided by NuGet). There's no simple single mscorlib that you can both compile and run against and expect to interop safely with other code.

Also, I should say that the C# compiler understands none of this: it just consumes reference assemblies and emits code. NuGet+project.json/msbuild coordinate behind the scenes to pick a specific set of reference assemblies to pass to the compiler and then coordinate to deploy the appropriate set of implementation DLLs for those references, along with the output from the compiler. The CoreCLR runtime handles the rest.

"All of this is to say: you're in a bit of a bind"

Is there any sort of plan to get this working?

I am trying to do scripting in .NET Core using Roslyn 1.3.2, and it works until I try to communicate with the script via my own classes in Global variable. (It is looking for System.Object in the System.Runtime.dll but can't find it, even if I reference it.)

At the moment, we have no plan to make it easy to use csc.exe in this manner. The guidance is to use the dotnet CLI tooling for the time being. Even if some modification where to be made here, it would be on the framework to provide unified and/or simplified reference assemblies for the compiler. The compiler will never have more complicated type or assembly resolution than it does now (by design).

@agocke I see. My concern is it is non-intuitive to ask the user to explicitly reference System.Runtime.dll / System.Private.Mscorlib.dll; Mscorlib contains a bunch of TypeForward declarations to other assemblies, so it has the information of where they might be.

The "ref" assemblies you speak from NuGet+project.json/msbuild of contain _actual_ definitions but no implementations; compare this to mscorlib which only contains TypeForward declarations. "~/.nuget/packages/Microsoft.NETCore.Portable.Compatibility/1.0.1/ref/netstandard1.0/mscorlib.dll" still only has TypeForward declarations. Should CSC (or whatever assembly reading library roslyn is using) not resolve TypeForward declarations? I could argue: what is the point of TypeForward declarations in mscorlib if there's not a "ref" mscorlib? Every tool/developer/whatever would have to manually probe mscorlib.dll, figure out which assemblies it references, and reference those directly should they want to use those types. At that point, does the IL generated say the type came from "System.Runtime.dll" or "mscorlib.dll"?

That said, if using an old mscorlib (say, from .NET Framework 4.X), presumably the above "csc Program.cs" scenario would work... although that requires understanding the default logic for finding mscorlib.dll (so that one could setup an environment where the default mscorlib found is the one you want) or always requiring"-nostdlib -reference:othermscorlib.dll".

@Imisnew2 Right, here's the problem:

My concern is it is non-intuitive to ask the user to explicitly reference System.Runtime.dll / System.Private.Mscorlib.dll

The design is that the user should _never explicitly reference anything_. csc is not meant to be used directly, its meant to be plugged into by a coordination or build system, like project.json + dotnet build/MSBuild.

And yes, you're correct that this is different from .NET desktop, where csc Program.cs is a valid and reasonably simple thing for a user to do. With the current CoreFX factoring and forwarding, this is just not a human-understandable amount of complexity.

@jaredthirsk Could you share more details on how you do scripting? This issue problem seems unrelated to scripting.

I'm having trouble getting Roslyn to find System.Object for my class.

I was trying http://www.strathweb.com/2016/03/roslyn-scripting-on-coreclr-net-cli-and-dnx-and-in-memory-assemblies/ so I could use my application's types in the scripting code:

The scripting APIs generally work just fine when you try to use them against .NET Core targets.

The problem arises when you are trying to pass in a reference to the current application assembly to your script. This can be needed for a number of reasons – for example you may want to use the results of the scripting operations in your main program or simply use the types from your main program inside the scripting code.

Here are some relevant snippets. Let me know if you want help debugging the full package to try yourself:
(It's on github at https://github.com/jaredthirsk/Core with LionFire.Execution.Program as the startup project)

public ScriptOptions Options {
    get {

        var options = ScriptOptions.Default
            .AddImports("System")
            .AddReferences("System.Runtime, Version=4.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a") // Doesn't work!?
            .AddReferences("System.Runtime") // Doesn't work!?
            .AddReferences("System.Private.Mscorlib") // Doesn't work!?
    #if NET461
                .AddReferences(typeof(System.Security.Cryptography.Aes).GetTypeInfo().Assembly) // Doesn't work!?
                    .AddReferences("System.Security.Cryptography.Algorithms") // Doesn't work!?
    #endif
                    .AddReferencesCore(typeof(MyGlobals).GetTypeInfo().Assembly)
            .AddReferencesCore(typeof(object).GetTypeInfo().Assembly) // Doesn't work!?
            .WithSourceResolver(new SourceFileResolver(ImmutableArray<string>.Empty, ScriptsDirectory))
            ;
        return options;
    }
}

public static unsafe ScriptOptions AddReferencesCore(this ScriptOptions options, Assembly assembly)
{
    // See http://www.strathweb.com/2016/03/roslyn-scripting-on-coreclr-net-cli-and-dnx-and-in-memory-assemblies/
#if NET461
            options.AddReferences(assembly);
#else
    byte* b;
    int length;
    if (assembly.TryGetRawMetadata(out b, out length))
    {
        var moduleMetadata = ModuleMetadata.CreateFromMetadata((IntPtr)b, length);
        var assemblyMetadata = AssemblyMetadata.Create(moduleMetadata);
        var result = assemblyMetadata.GetReference();
        options.AddReferences(result);
    }
    else
    {
        throw new Exception("Failed to get raw metadata for assembly: " + assembly.FullName);
    }
#endif
    return options;
}

Microsoft.CodeAnalysis.Scripting.Hosting.InteractiveAssemblyLoader loader = new Microsoft.CodeAnalysis.Scripting.Hosting.InteractiveAssemblyLoader();

public Task<bool> Initialize()
{
    //CSharpScriptEngine.Execute( // new Roslyn 2.x API?
    script = Microsoft.CodeAnalysis.CSharp.Scripting.CSharpScript.Create(myCSharpCodeString
    , Options
#if GLOBALS
        , typeof(MyGlobals)
#endif
        , loader
    );

    return Task.FromResult(script != null);
}


public Task Start()
{
    cts = new System.Threading.CancellationTokenSource();
#if GLOBALS
    var roslynRunTask = script.RunAsync(new MyGlobals(), cts.Token); // Object type not found, please add reference to System.Runtime, Version=4.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
#else
        var roslynRunTask = script.RunAsync(cancellationToken:cts.Token);
#endif
    // ...
}

public class MyGlobals
{
    public string A = "123";
    public int B = 456;
}

Script contains some irrelevant stuff then this: return A + " got global!";

Exception: AggregateException with InnerException of

{Microsoft.CodeAnalysis.Scripting.CompilationErrorException: (1,7): error CS0012: The type 'Object' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Runtime, Version=4.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'.
   at Microsoft.CodeAnalysis.Scripting.ScriptBuilder.ThrowIfAnyCompilationErrors(DiagnosticBag diagnostics, DiagnosticFormatter formatter)
   at Microsoft.CodeAnalysis.Scripting.ScriptBuilder.CreateExecutor[T](ScriptCompiler compiler, Compilation compilation, CancellationToken cancellationToken)
   at Microsoft.CodeAnalysis.Scripting.Script`1.GetExecutor(CancellationToken cancellationToken)
   at Microsoft.CodeAnalysis.Scripting.Script`1.RunAsync(Object globals, Func`2 catchException, CancellationToken cancellationToken)
   at Microsoft.CodeAnalysis.Scripting.Script`1.RunAsync(Object globals, CancellationToken cancellationToken)
   at LionFire.Execution.Roslyn.Scripting.RoslynScriptExecutionController.Start()
   at LionFire.Execution.ExecutionContextExtensions.<Start>d__1.MoveNext()}

Thanks @agocke. I guess you can close issue this as user-error, the solution being: figure out what to reference and reference it. Although, documentation surrounding how to invoke csc after building the repo would be nice, though.

For example... previous csc, as a minimum, only needed mscorlib (Microsoft Core Library?), and even then, it /really/ only needed certain types to be defined therein. Could the required types be documented, and, or at the very least, document which assemblies (that would contain the required types) should always be referenced if using the .NETCore framework?

Thanks for the replies, all.

Anyone have any idea how I can get the CompilationErrorException "The type 'Object' is defined in an assembly that is not referenced." to go away?

@jaredthirsk in general this error occurs because the compiler is not given a reference to mscorlib or System.Runtime (which depends on the type of project being compiled). Can you give us a bit more information about what the project structure is?

@jaredpar The project is .NET Core, using Roslyn 1.3.2. What else do you need to know? Has anyone been able to get scripting working in .NET Core using Roslyn 1.3.2? If so, what references do they use? I understand .NET Core has a different system of reference assemblies and implementation assemblies and I'm not sure how to feed both to Roslyn.

My full project is up at:

(It's on github at https://github.com/jaredthirsk/Core with LionFire.Execution.Program as the startup project)

@jaredthirsk I have tried run the project but I see this error:

TEMP - Failed to load class LionFire.Environment.CommandLine.LionEnvironmentCliHandlers, LionFire.Environment.CommandLine, Version=0.1.0.0
test: LionFire.CommandLine.CommandLineArgs, LionFire.CommandLine, Version=0.1.0.0, Culture=neutral, PublicKeyToken=null
Exception loading assembly: E:\src\Trading\src\LionFire.Trading.Feeds.TrueFx\bin\Debug\netstandard1.6\TestLx.cs.dll
System.IO.DirectoryNotFoundException: The system cannot find the path specified. (Exception from HRESULT: 0x80070003)
   at System.Runtime.Loader.AssemblyLoadContext.LoadFromPath(IntPtr ptrNativeAssemblyLoadContext, String ilPath, String niPath, ObjectHandleOnStack retAssembly)
   at System.Runtime.Loader.AssemblyLoadContext.LoadFromAssemblyPath(String assemblyPath)
   at LionFire.Execution.Initialization.LocalAssemblyFromUriResolver.<>c__DisplayClass3_0.<ResolveAssemblyFromName>b__0() in D:\Temp\JT\src\LionFire.Execution\Execution\Initialization\Assembly\LocalAssemblyFromUriResolver.cs:line 77

Unhandled Exception: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.AggregateException: One or more errors occurred. (nuget support coming soon) ---> System.NotImplementedException: nuget support coming soon
   at LionFire.Execution.Initialization.AssemblyFromNugetResolver.Resolve(ExecutionConfig config)
   at LionFire.Execution.Initialization.ExecutionConfigResolver.<ResolveSourceContent>d__7.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at LionFire.Execution.Initialization.ExecutionInitializer.<Initialize>d__1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at LionFire.Execution.ExecutionContextExtensions.<Initialize>d__0.MoveNext()
   --- End of inner exception stack trace ---
   at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)
   at System.Threading.Tasks.Task.Wait(Int32 millisecondsTimeout, CancellationToken cancellationToken)
   at System.Threading.Tasks.Task.Wait()
   at LionFire.Execution.Hosting.ExecutionHostConsoleApp.Start(String[] args)
   --- End of inner exception stack trace ---
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
   at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)
   at LionFire.CommandLine.Dispatching.CliDispatcher.RunHandler(MethodInfo handler, Object instance, Object context, String[] args, CommandLineArgs cla)
   at LionFire.CommandLine.Dispatching.CliDispatcher.Dispatch(String[] args, Object handlerInstance, Type handlerClass, Object context, CliDispatcherOptions options)
   at LionFire.Applications.CommandLine.ConsoleApp.Run(String[] args)
   at LionFire.Execution.Hosting.Program.Main(String[] args)

Could you please create a simple project that directly demonstrates the loading issue?

I have a similar issue. No matter what I try I get the error message that System.Object cannot be found and I need to import System.Runtime.

[email protected]:GeirGrusom/RoslynScript.git

@tmat @jaredpar Sorry I have been busy with other things, but GeirGrusom provided a simple example above of the failed resolution of System.Object in .NET Core.

I had the same kind of issue with decimal not being defined (missing reference to System.Runtime, Version=4.0.20.0). I've written a blog post with a workaround.

@epsitec Have you tried the latest version 2.0.0-rc3?

@tmat I can confirm that even when using 2.0.0-rc3 I still see this if I only specify ScriptOptions.Default:

{"(1,1): error CS0012: The type 'Object' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Runtime, Version=4.0.20.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'."}

Can you share your project?

I'll extract the code into a stand-alone solution in order to share the sample, yes.

@tmat it took me longer than I expected to be able to reproduce the issue outside of our product.
The crash is related to the type used for the _globals_. I had to set up three projects:

  • Console → .NET Framework 4.6 - defines class Mine
  • Context → .NET Standard 1.3 - defines class Globals
  • Library → .NET Standard 1.3 - defines class Locals

Calling the script compiler with instances of Mine or Locals works fine.
Calling it with an instance of Globals produces this exception:

The type 'Decimal' is defined in an assembly that is not referenced.
You must add a reference to assembly 'System.Runtime, Version=4.0.20.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'.

Here is the sample project: https://github.com/epsitec/rnd-csharpscript-netstandard

Thanks, I'll take a look.

@epsitec Concerning your blog post. I was able to take what you wrote and get your sample working.
However, as soon as I use a DateTime time, I am back to the same error. Any ideas?

The type 'DateTime' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Runtime, Version=4.0.20.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
public static string GetAssemblyLoadPath(this System.Type type)
{
    return ServiceLocator.AssemblyLoader.GetAssemblyLoadPath (type.GetTypeInfo ().Assembly);
}

Not sure what service locator is, so assume you just meant:

public static string GetAssemblyLoadPath(this System.Type type)
{
    return type.Assembly.Location;
}

Additionally, not that it matters, but your example code
var script = CSharpScript.Create<int> ("42m", options: options, globalsType: typeof (Globals));
should be
var script = CSharpScript.Create<decimal> ("42m", options: options, globalsType: typeof (Globals));

@tmat Hope you are finding the answer. If you install a package that uses .NET Standard and csharpscript, it is broken.

Well, what I said was not exactly true. It does work for DateTime. What I am running into is I have a simple extension defined in a class library in a nuget package like this:

public static DateTime GetFirstDateOfMonth(this DateTime date)
{
    return new DateTime(date.Year, date.Month, 1);
}

That class library takes a dependency on .net standard 1.4.

If I try to run a script that uses that extension it fails with the DateTime type issue. If I define that same extension, it works just fine. So referencing any code in a library that depends on .net standard is broken.

All these are fine, except the last which says I need a reference to ``System.Runtime, Version=4.0.20.0"

var script1 = CSharpScript.EvaluateAsync<DateTime>("System.DateTime.Parse(\"12/15/2012\")", DefaultOptions);
var script2 = CSharpScript.EvaluateAsync<DateTime>("System.DateTime.Today", DefaultOptions);
var script3 = CSharpScript.EvaluateAsync<DateTime>("new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1)", DefaultOptions);
var script4 = CSharpScript.EvaluateAsync<DateTime>("System.DateTime.Today.GetFirstDateOfMonthLocallyDefined()", DefaultOptions);
var script5 = CSharpScript.EvaluateAsync<DateTime>("System.DateTime.Today.GetFirstDateOfMonth()", DefaultOptions);

@waynebrantley the initial analysis in my blog post was based on the wrong assumptions. I really need to include multiple .NET Standard projects for the error to show up, as I have demonstrated in the sample solution found at https://github.com/epsitec/rnd-csharpscript-netstandard (and as you found out, this has something to do with referencing code in .NET Standard libraries).

By the way, you are right, ServiceLocator.AssemblyLoader calls into code which comes from our framework and allows us to reach into Assembly.Location, even on .NET Standard 1.x where Location is not available.

@jinujoseph can you re-triage? This was in the 2.0 milestone.

I think there is a lot of confusion around referencing .NET Core libraries. Runtime code generation using Roslyn compilations in .NET Core App clarifies.

It would definitely be desirable to make it simpler to avoid above issues.

pls references 💯 👍👏
https://github.com/dotnet/sdk/issues/8742#issuecomment-744126710

This is the scripts:

`

#!/bin/bash

#dotnethome=`dirname "$0"`
dotnethome=`dirname \`which dotnet\``
sdkver=$(dotnet --version)
fwkver=$(dotnet --list-runtimes | grep Microsoft.NETCore.App | awk '{printf("%s", $2)}')
dotnetlib=$dotnethome/shared/Microsoft.NETCore.App/$fwkver

if [ "$#" -lt 1 ]; then
    dotnet $dotnethome/sdk/$sdkver/Roslyn/bincore/csc.dll -help
    echo dotnethome=$dotnethome
    echo sdkver=$sdkver
    echo fwkver=$fwkver
    echo dotnetlib=$dotnetlib
    exit 1
fi

progfile=$1
prog="${progfile%.*}"
echo -r:$dotnetlib/netstandard.dll > /tmp/$prog.rsp
echo -r:$dotnetlib/System.dll >> /tmp/$prog.rsp
echo -r:$dotnetlib/Microsoft.CSharp.dll >> /tmp/$prog.rsp
for f in  $dotnetlib/System.*.dll; do
    echo -r:$f >> /tmp/$prog.rsp
done

dotnet $dotnethome/sdk/$sdkver/Roslyn/bincore/csc.dll -out:$prog.dll -nologo @/tmp/$prog.rsp $* 
if [ $? -eq 0 ]; then
#  if test -f "$prog.exe"; then
   if test -f "$prog.dll"; then
    if ! test -f "$prog.runtime.config"; then
        echo "{
  \"runtimeOptions\": {
    \"framework\": {
      \"name\": \"Microsoft.NETCore.App\",
      \"version\": \"$fwkver\"
    }
  }
}"  > "$prog.runtimeconfig.json"
    fi
  fi
fi
echo /tmp/$prog.rsp: 
cat /tmp/$prog.rsp
rm /tmp/$prog.rsp


`

NET Core SDK (reflecting any global.json):
Version: 3.1.100
Commit: cd82f021f4

Runtime Environment:
OS Name: ubuntu
OS Version: 20.04
OS Platform: Linux
RID: linux-x64
Base Path: /root/dotnet/sdk/3.1.100/

Host (useful for support):
Version: 3.1.0
Commit: 65f04fb6db

.NET Core SDKs installed:
3.1.100 [/root/dotnet/sdk]

.NET Core runtimes installed:
Microsoft.AspNetCore.App 3.1.0 [/root/dotnet/shared/Microsoft.AspNetCore.App]
Microsoft.NETCore.App 3.1.0 [/root/dotnet/shared/Microsoft.NETCore.App]

To install additional .NET Core runtimes or SDKs:
https://aka.ms/dotnet-download

@kinglionsz can you explain what problem you are hitting here?

If you are getting the same message as the title of this issue then the problem is that your script is not passing the correct set of reference assemblies to the compiler. In general we do not recommend directly invoking the compiler in this way because getting the correct set of references is quite challenging when you take into account all of the scenarios that .NET supports. Instead we strongly recommend that you use an MSBuild file to drive the compiler.

Yes. I understand. Thank you so much. @jaredpar

@kinglionsz can you explain what problem you are hitting here?

If you are getting the same message as the title of this issue then the problem is that your script is not passing the correct set of reference assemblies to the compiler. In general we do not recommend directly invoking the compiler in this way because getting the correct set of references is quite challenging when you take into account all of the scenarios that .NET supports. Instead we strongly recommend that you use an MSBuild file to drive the compiler.

It would be much easier to teach c# to a beginner if source files could be directly compiled without requiring msbuild.

Was this page helpful?
0 / 5 - 0 ratings