Sdk: Basic use of AssemblyLoadContext on supported frameworks doesn't work

Created on 12 Mar 2017  路  29Comments  路  Source: dotnet/sdk

Steps to reproduce

  • Create a new solution in VS 2017
  • Add a .NET core class library that targets NETStandard 1.3 framework and uses NETStandard 1.3 library
  • Add a package reference to System.Runtime.Loader
  • Create a class that uses AssemblyLoadContext

  • Add a .NET 4.6.2 console app project

  • Add a reference to the .NET Core class library
  • Use the aforementioned class from the class library in the console app

Expected behavior

Works

Actual behavior

Could not load load assembly System.Runtime.Loader

My understanding is

  • .NET 4.6.2 implements the .NET Standard 1.3 spec
  • The System.Runtime.Loader package (per nuget package manager) doesn't have any runtime restrictions listed that I see and it says it supports BOTH .NET Standard 1.5 (grandfathering in 1.3) AND .NET 4.6.2 frameworks (the second framework support shouldn't be necessary, given the first)

Even adding a direct package reference from the .NET 4.6.2 console app doesn't help.

What's going on here? Is the documentation for this package wrong? Is there a bug in the package? Does .NET Standard still not work at basic things like this?

Most helpful comment

I don't see the warnings from the guardrails in my PackageReference projects. It sounds like this problem is now understood.
I also don't "publish" my projects. I just pack them. And I don't see warnings when I do this. So I manage to get through the entire development and publishing to nuget.org workflow without seeing any warnings. This seems badly broken.

the package just happens to use that tfm to share its reference asssembly between more than one framework.

What is the good of specifying netstandard support for this package if no one targeting netstandard should be able to reference the package? It's netcoreapp1.0 specific so it should only claim support for that.

If there is something here what we actually want to do for 2.0, please re-activate. From the thread it seems like we don't need these for 2.0.

Why don't we care about the 1.x world? 2.0 isn't here yet, and even when it's here, netstandard1.x is still very interesting because it means our libraries can support older platform versions. I for one am not planning on targeting .netstandard2.0 any time soon for projects that don't absolutely require it. As System.Runtime.Loader 1.x is going to be on nuget.org forever, doesn't it behoove us to ship a newer 1.x version of the package that drops claims of netstandard/net462 support so that when folks see it on nuget.org and try to install the latest stable package it will block them unless they're targeting netcoreapp specifically?

All 29 comments

System.Runtime.Loader does not work on full .NET Framework. I don't understand why the package is authored as it is (it has an empty lib folder for net462).

@ericstj

So the package is bugged?

And further - if you're publishing a nuget target of the netstandard1.5 framework (which is implemented by .NET 4.6.2), that framework target is bugged too, since you haven't added a platform requirement of CoreCLR.

Can you confirm these statements are correct?

I don't understand why the package is authored as it is (it has an empty lib folder for net462).

An empty lib with a dll for ref is an indication of "not supported" which NuGet flags on install and restore. https://github.com/NuGet/NuGet.Client/blob/dev/src/NuGet.Core/NuGet.Commands/RestoreCommand/CompatibilityChecker.cs#L38-L58

Nuget gave me no problem installing it via the package manager console for a 4.6.2 project. Further, see above points on lack of platform restriction

The System.Runtime.Loader package (per nuget package manager) doesn't have any runtime restrictions listed that I see and it says it supports BOTH .NET Standard 1.5 (grandfathering in 1.3) AND .NET 4.6.2 frameworks (the second framework support shouldn't be necessary, given the first)

How did you determine that it "supports" those versions. It isn't part of the NETStandard.Library closure, the package just happens to use that tfm to share its reference asssembly between more than one framework. Wether or not its actually supported relies on that ref/lib check I pointed out in NuGet's restore code. Let me know with a specific link where you were led to believe it would support desktop and we'll try and get that cleared up.

Regardless, the answer here is that this package is not supported on desktop and the package is going away with V2 so there isn't anything for us to fix. The only way you'll be able to use this API in v2 will be from the NETCore.App package.

Can you let me know if you need any more information?

I understand the answer. What I don't understand then is why it let me add this package from my 4.6.2 project.

It's a side effect of NuGet's packages.config behavior. It let the package install but doesn't provide the API. This is because NuGet doesn't do the ref/lib check for packages.config. All it sees is the lib placeholder and permits the package to install without providing anything.

We could do something in the package to explicitly block this (potentially a breaking change) but given we aren't going to ship this package in the next release (and will unlist the old packages) I'm not sure we have a good justification for doing so since we'd need to do so in our servicing releases.

The sort of thing we could do in the servicing release is either a) remove the netstandard ref and make it netcoreapp only, a breaking change, or b) ship an assembly for desktop that throws for all the API.

@ericstj This doesn't seem to be related to packages.config, I am able to install System.Runtime.Loader 4.3.0 into a project targeting .NET 4.6.2 that has opted into PackageReference style references.

@dsplaisted that would indicate that NuGet dropped the ref/lib matching code from https://github.com/NuGet/NuGet.Client/blob/dev/src/NuGet.Core/NuGet.Commands/RestoreCommand/CompatibilityChecker.cs#L38-L58 in their PackageReference restore implementation. Either that or the warning/error is buried in restore tracing.

@ericstj The System.Runtime.Loader package has a libnet462 folder with a _._ file in it. Given that, would you expect an installation or restore failure for the package?

Again, based on ref/lib mismatch we'd expect a failure in the compatibility checker code. That's what happened in nuget3.

@emgarten @rrelyea @natidea @eerhardt @nguerrera Based on what @ericstj is saying, it sounds like NuGet may no longer be checking that there is an implementation to match a reference assembly from a NuGet package. Is this expected?

That's correct, the guardrails checks for runtime assemblies is turned off for PackageReference. Publish should add support for verifying this where all the information is available.

@emgarten Is there a bug filed anywhere to add this check to publish?

I'm not sure we care so much about it moving forward. The old packages that were designed for NuGet 3 relied on this (guardrails) behavior but the new packages for netcoreapp2.0 do not.

If there is something here what we actually want to do for 2.0, please re-activate. From the thread it seems like we don't need these for 2.0.

I don't see the warnings from the guardrails in my PackageReference projects. It sounds like this problem is now understood.
I also don't "publish" my projects. I just pack them. And I don't see warnings when I do this. So I manage to get through the entire development and publishing to nuget.org workflow without seeing any warnings. This seems badly broken.

the package just happens to use that tfm to share its reference asssembly between more than one framework.

What is the good of specifying netstandard support for this package if no one targeting netstandard should be able to reference the package? It's netcoreapp1.0 specific so it should only claim support for that.

If there is something here what we actually want to do for 2.0, please re-activate. From the thread it seems like we don't need these for 2.0.

Why don't we care about the 1.x world? 2.0 isn't here yet, and even when it's here, netstandard1.x is still very interesting because it means our libraries can support older platform versions. I for one am not planning on targeting .netstandard2.0 any time soon for projects that don't absolutely require it. As System.Runtime.Loader 1.x is going to be on nuget.org forever, doesn't it behoove us to ship a newer 1.x version of the package that drops claims of netstandard/net462 support so that when folks see it on nuget.org and try to install the latest stable package it will block them unless they're targeting netcoreapp specifically?

Is there a separate issue tracking the lack of NuGet errors/warnings in this scenario? If not, can this be reactivated?

In a .NET 4.7.2 WinForms app, it's possible to add a System.Runtime.Loader reference (using either packages.config or PackageReference) using the 'Manage NuGet Packages' UI in VS. Both successfully add the reference. The project can be built, published, etc. and never produce a warning or error that the package is unsupported on NetFx. The only way to find that out is to notice that the types from the package aren't available at build-time (or, if they come from a NetStandard dependency, there would presumably be a runtime error).

It seems entirely possible that a developer would want to share code using AssemblyLoadContext between NetCore and NetFx scenarios and not be sure whether ALC works on both platforms or not, so they would try to add the package reference to "see what happens". In this case, things would appear to work and lead the developer down the wrong path.

Also, I thought this might just be a problem with the old project file format, so I tried with the new one and it has the same issue. I created a console app (using dotnet new console), targeted net472 and was able to add a reference to System.Runtime.Loader, build, publish, and run the app and only saw an error at runtime:

D:\temp\t1
位 dotnet add package System.Runtime.Loader
  Writing C:\Users\mikerou\AppData\Local\Temp\tmpE8B8.tmp
info : Adding PackageReference for package 'System.Runtime.Loader' into project 'D:\temp\t1\t1.csproj'.
log  : Persisting no-op dg to D:\temp\t1\obj\t1.csproj.nuget.dgspec.json
info : Restoring packages for D:\temp\t1\t1.csproj...
info :   CACHE https://api.nuget.org/v3-flatcontainer/system.runtime.loader/index.json
info :   GET https://dotnetfeed.blob.core.windows.net/aspnet-aspnetcore-tooling/flatcontainer/system.runtime.loader/index.json
info :   GET https://dotnetfeed.blob.core.windows.net/aspnet-aspnetcore/flatcontainer/system.runtime.loader/index.json
info :   GET https://dotnetfeed.blob.core.windows.net/aspnet-entityframeworkcore/flatcontainer/system.runtime.loader/index.json
info :   GET https://dotnetfeed.blob.core.windows.net/aspnet-extensions/flatcontainer/system.runtime.loader/index.json
info :   CACHE https://dotnetfeed.blob.core.windows.net/dotnet-core/flatcontainer/system.runtime.loader/index.json
info :   GET https://dotnetfeed.blob.core.windows.net/dotnet-windowsdesktop/flatcontainer/system.runtime.loader/index.json
info :   NotFound https://dotnetfeed.blob.core.windows.net/dotnet-windowsdesktop/flatcontainer/system.runtime.loader/index.json 441ms
info :   NotFound https://dotnetfeed.blob.core.windows.net/aspnet-extensions/flatcontainer/system.runtime.loader/index.json 464ms
info :   NotFound https://dotnetfeed.blob.core.windows.net/aspnet-aspnetcore-tooling/flatcontainer/system.runtime.loader/index.json 687ms
info :   NotFound https://dotnetfeed.blob.core.windows.net/aspnet-aspnetcore/flatcontainer/system.runtime.loader/index.json 486ms
info :   NotFound https://dotnetfeed.blob.core.windows.net/aspnet-entityframeworkcore/flatcontainer/system.runtime.loader/index.json 474ms
info : Package 'System.Runtime.Loader' is compatible with all the specified frameworks in project 'D:\temp\t1\t1.csproj'.
info : PackageReference for package 'System.Runtime.Loader' version '4.3.0' added to file 'D:\temp\t1\t1.csproj'.
info : Committing restore...
info : Writing assets file to disk. Path: D:\temp\t1\obj\project.assets.json
log  : Restore completed in 1.03 sec for D:\temp\t1\t1.csproj.

D:\temp\t1
位 cat t1.csproj
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net472</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="System.Runtime.Loader" Version="4.3.0" />
  </ItemGroup>

</Project>

D:\temp\t1
位 dotnet publish
Microsoft (R) Build Engine version 16.1.27-preview+g91af6445a6 for .NET Core
Copyright (C) Microsoft Corporation. All rights reserved.

  Persisting no-op dg to D:\temp\t1\obj\t1.csproj.nuget.dgspec.json
  Restore completed in 119.92 ms for D:\temp\t1\t1.csproj.
C:\Program Files\dotnet\sdk\3.0.100-preview4-010932\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.RuntimeIdentifierInference.targets(151,5): message NETSDK1057: You are using a preview version of .NET Core. See: https://aka.ms/dotnet-core-preview [D:\temp\t1\t1.csproj]
  t1 -> D:\temp\t1\bin\Debug\net472\t1.exe
  t1 -> D:\temp\t1\bin\Debug\net472\publish\

D:\temp\t1
位 .\bin\Debug\net472\t1.exe

Unhandled Exception: System.IO.FileNotFoundException: Could not load file or assembly 'System.Runtime.Loader, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The system cannot find the file specified.
   at t1.Program.Main(String[] args)

I don't know if there's an issue, but the fix would have to be either in the package authoing (dotnet/corefx) or in NuGet (NuGet/Home).

(using either packages.config or PackageReference)

@ericstj Can you comment. This contradicts the earlier statement that the symptom was limited to packages.config.

Does this mean NuGet has something wrong or is there actually something wrong with the package. Based on the answer we can reopen and move this bug appropriately.

That comment was made two years ago when nuget did the matching ref/lib check. Nuget removed that check so now they permit it to install. The check was removed after this package shipped then we dead ended the package since it became part of NETCoreApp framework package and thus it no longer needed a package.

There is really no good reason to use this package. It could be updated from 1.x servicing but it鈥檚 hard to justify an update just to make it fail.

I see. Thanks for clarifying, @ericstj. In this case, I think the package was picked up to try and use AssemblyLoadContext on .NET Framework (since, as you say, the package is already built into the NETCoreApp framework, so it isn't needed on .NET Core). It would be nice if we could somehow mark the package as obsolete to avoid this sort of confusion, but I agree that it's probably not worth the effort for any sort of complicated fix since it's specific to this particular package which is dead-ended.

Just got bitten by this in .net 4.7.2, I wrote AssemblyLoadContext.Default.LoadFromStream and visual studio _suggested_ installing System.Runtime.Loader, which succeeded, but nothing changed.

on asp.net core 2.2 in VS2019 I get this warning on every run:

Microsoft Visual Studio

To prevent an unsafe abort when evaluating the function 'System.Runtime.Loader.AssemblyLoadContext.LoadFromAssemblyPath' all threads were allowed to run. This may have changed the state of the process and any breakpoints encountered have been skipped.

OK Help

@tovli Please open a new issue for that. It is a different problem and this issue is closed.

ok
Thanks.

I'm getting this error when building a UWP from Unity. Not sure if it is related. If not, please point me in the right direction. Thanks:

Reference rewriter: Error: type `System.Runtime.Loader.AssemblyLoadContext` doesn't exist in target framework. It is referenced from Microsoft.CodeAnalysis.Scripting.dll at Microsoft.CodeAnalysis.Scripting.Hosting.CoreAssemblyLoaderImpl/LoadContext.
UnityEngine.Debug:LogError(Object)
PostProcessWinRT:RunReferenceRewriter() (at C:/buildslave/unity/build/PlatformDependent/MetroPlayer/Extensions/Managed/PostProcessWinRT.cs:1164)
PostProcessWinRT:Process() (at C:/buildslave/unity/build/PlatformDependent/MetroPlayer/Extensions/Managed/PostProcessWinRT.cs:206)
UnityEngine.GUIUtility:ProcessEvent(Int32, IntPtr) (at C:/buildslave/unity/build/Modules/IMGUI/GUIUtility.cs:179)

The nuget packages really should be deprecated. That would save people from wasting a lot of time...

The nuget packages really should be deprecated. That would save people from wasting a lot of time...

I disagree. I had a function to run this on a Class Library with netstandard2.0 and it wasn't found. This issue helped me to figure out that I had to install the System.Runtime.Loader package to get it working:

            AssemblyLoadContext.Default.Unloading += (AssemblyLoadContext obj) =>
            {
                Console.WriteLine("ASSEMBLY LOAD CONTEXT UNLOADING");
                Console.WriteLine($"{obj}");
            };

I had to install the System.Runtime.Loader package to get it working

@darkguy2008, your library might target .NET Standard 2.0 but it doesn't work with all frameworks .NET Standard 2.0 supports. Using this library on a .NET Framework project will cause a crash. I suggest you uninstall the package from your library and directly target .NET Core (or even better .NET 5 if you can).

See dotnet/runtime#38503.

Was this page helpful?
0 / 5 - 0 ratings