Standard: Design time build causes "Cannot load a reference assembly for execution."

Created on 24 Oct 2018  路  15Comments  路  Source: dotnet/standard

On .NET 4.7.2, VS 15.8.7, Windows 7 it is very easily possible to encounter the given error message. The error is caused by a design time build. Repro:

  1. Create new MVC web app.
  2. Add library project and reference it.
  3. Add System.Net.Http NuGet package to both projects.
  4. Update all NuGet packages.
  5. Uncomment all HTTP modules from web.config. There is another bug there that prevents the application from loading because the telemetry system cannot load System.Net.Http. This ticket is not about that bug.

That's the entire setup. Now press F5 to confirm that the application runs.

Now restart Visual Studio. This triggers a design time build (I believe) which copies additional (wrong) DLLs to the bin directory. A sign that this is happening is that System.Security.Cryptography.Primitives.dll appears in the bin directory of the web app. Note, that no build was needed. Just starting VS did this.

If you press F5 now the following error is given:

Cannot load a reference assembly for execution.

[BadImageFormatException: Cannot load a reference assembly for execution.]

[BadImageFormatException: Could not load file or assembly 'System.Net.Http' or one of its dependencies. Reference assemblies should not be loaded for execution.  They can only be loaded in the Reflection-only loader context. (Exception from HRESULT: 0x80131058)]
   System.Reflection.RuntimeAssembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, RuntimeAssembly locationHint, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks) +0
   System.Reflection.RuntimeAssembly.nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, RuntimeAssembly locationHint, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks) +36
   System.Reflection.RuntimeAssembly.InternalLoadAssemblyName(AssemblyName assemblyRef, Evidence assemblySecurity, RuntimeAssembly reqAssembly, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks) +152
   System.Reflection.RuntimeAssembly.InternalLoad(String assemblyString, Evidence assemblySecurity, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean forIntrospection) +77
   System.Reflection.RuntimeAssembly.InternalLoad(String assemblyString, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection) +21
   System.Reflection.Assembly.Load(String assemblyString) +28
   System.Web.Configuration.CompilationSection.LoadAssemblyHelper(String assemblyName, Boolean starDirective) +38

[ConfigurationErrorsException: Could not load file or assembly 'System.Net.Http' or one of its dependencies. Reference assemblies should not be loaded for execution.  They can only be loaded in the Reflection-only loader context. (Exception from HRESULT: 0x80131058)]
   System.Web.Configuration.CompilationSection.LoadAssemblyHelper(String assemblyName, Boolean starDirective) +726
   System.Web.Configuration.CompilationSection.LoadAllAssembliesFromAppDomainBinDirectory() +196
   System.Web.Configuration.CompilationSection.LoadAssembly(AssemblyInfo ai) +45
   System.Web.Compilation.BuildManager.GetReferencedAssemblies(CompilationSection compConfig) +172
   System.Web.Compilation.BuildManager.GetPreStartInitMethodsFromReferencedAssemblies() +91
   System.Web.Compilation.BuildManager.CallPreStartInitMethods(String preStartInitListPath, Boolean& isRefAssemblyLoaded) +111
   System.Web.Compilation.BuildManager.ExecutePreAppStart() +156
   System.Web.Hosting.HostingEnvironment.Initialize(ApplicationManager appManager, IApplicationHost appHost, IConfigMapPathFactory configMapPathFactory, HostingEnvironmentParameters hostingParameters, PolicyLevel policyLevel, Exception appDomainCreationException) +695

[HttpException (0x80004005): Could not load file or assembly 'System.Net.Http' or one of its dependencies. Reference assemblies should not be loaded for execution.  They can only be loaded in the Reflection-only loader context. (Exception from HRESULT: 0x80131058)]
   System.Web.HttpRuntime.FirstRequestInit(HttpContext context) +659
   System.Web.HttpRuntime.EnsureFirstRequestInit(HttpContext context) +89
   System.Web.HttpRuntime.ProcessRequestNotificationPrivate(IIS7WorkerRequest wr, HttpContext context) +188

You can confirm that the VS restart causes this:

  1. Start VS.
  2. Delete all bin/obj folders.
  3. Press F5.

The application runs. If you now restart VS again it starts to fail permanently.

I was not sure where to open this issue. Is this a System.Net.Http bug or a tooling bug? Seems tooling to me.

We are hitting this with our production application at the moment. We must clear the bin/obj folders after each restart of VS.

documentation netfx-compat

Most helpful comment

Ok, so after more investigating and the help from @ericstj we found that it is defintely the ASP.NET project system what is causing this issue. We also found a workaround for you without the need of migrating to PackageReference. Today, the references to some of your NuGet packages in your .csproj look like the following System.Net.Http one:

    <Reference Include="System.Net.Http, Version=4.1.1.3, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
      <HintPath>..\packages\System.Net.Http.4.3.4\lib\net46\System.Net.Http.dll</HintPath>
      <Private>True</Private>
      <Private>True</Private>
    </Reference>

What is causing this issue is those two Metadata items that say <Private>True</Private>. If you remove them you will not be able to see this issue any longer. What is happening is that when the web project is loaded, the project system will run a process (and this is not the design time build) which will do some web application specific tasks, including the call to the following method: EnsureCopyLocalAssembliesAreInBinAtFirstIdle. As its name describes, this method will try to copy the files you will need at runtime into the bin folder. The problem here, is that the System.Net.Http that you referenced in your project(the nuget package one), will be replaced with the Reference assembly from our 4.7.2 targeting pack because it has a higher assembly version, but the web project system doesn't realize that this is now the framework version, so it merges the metadata (meaning it merges the Private=True metadata in your .csproj) and copies this file (the reference assembly from our targeting pack) anyway to the bin folder. By removing the metadata from the .csproj, your project will behave properly and use the right assembly at runtime from the framework. We will chat with the folks at the web project system to see if they can come up with a fix for this.

All 15 comments

I'm tracking related issues and information in a list. They are related to System.Net.Http, System.Runtime, System.IO, System.ValueTuple, System.Buffers and others.

https://github.com/dotnet/corefx/issues/32587
https://github.com/dotnet/corefx/issues/32561
https://github.com/dotnet/standard/issues/481
https://github.com/dotnet/standard/issues/567
https://github.com/dotnet/standard/issues/558
https://github.com/dotnet/standard/issues/887
https://github.com/dotnet/standard/issues/891
https://github.com/dotnet/corefx/issues/32610
https://github.com/dotnet/corefx/issues/30642
https://github.com/dotnet/corefx/issues/32757
https://github.com/dotnet/standard/issues/895
https://github.com/dotnet/standard/issues/877
https://github.com/dotnet/standard/issues/521
https://github.com/dotnet/standard/issues/295
https://github.com/dotnet/standard/issues/476
https://github.com/dotnet/standard/issues/184
https://github.com/dotnet/standard/issues/936
https://github.com/dotnet/standard/issues/941
https://github.com/dotnet/corefx/issues/33148
https://github.com/NuGet/Home/issues/7440
https://github.com/dotnet/corefx/issues/31532
https://github.com/dotnet/corefx/issues/22781
https://github.com/dotnet/corefx/issues/23306
https://github.com/dotnet/corefx/issues/29622
https://github.com/dotnet/corefx/issues/9846
https://github.com/dotnet/corefx/issues/17522
https://github.com/dotnet/corefx/issues/25773

All of these have the same very few underlying issues.

.NET 4.7.2 helps with some but not all of these. You can look at my comments on some of these issues for some ideas on how to work around those problems. I also have a central list of ideas to try.

It is not clear from our instructions, and we are working on how to fix it but System.Net.Http package should NOT be referenced from an application that targets .NET Framework. System.Net.Http ships with the framework so it is installed in the GAC, similar to mscorlib.dll. For this reason, applications and libraries targeting .NET Framework should reference the inbox version instead (meaning a regular <Reference Include="System.Net.Http" /> in your csproj or adding it through the solution explorer.) That should at least avoid the issues you are seeing for this particular scenario, but that said, I'm going to investigate what is causing the design time build to corrupt the bin/obj folders so that you need to delete them every time.

I just tried exactly the above repro steps and I wasn't able to repro. if you could share a sample solution with this problem that I can just open in VS and get into the state, it would be great for investigating.

I did not know that System.Net.Http is not supposed to be referenced. But should it not at least be benign to do that? Also, what if new features or fixes are released that I want to use? You said that you are working to fix that and maybe that's what you meant.

I tried my repro in a fairly clean Windows 10 VM with the latest updates on VS 15.8.8 with .NET 4.7.2. Simply starting VS places these files into the /bin directory:

image

But building does not. To get to a clean state, delete bin/obj. I will attach the solution.

DesignTimeBuildRepro.zip

@joperezr can you please try this one? Per https://github.com/NuGet/Home/issues/7440#issuecomment-498239011 it reproduces with 4.7.2 which is unexpected ...

I was able to reproduce this error while running in 4.7.2. Seems like this is a bug in the tooling where they are copying the wrong file into the bin folder, as they are copying a reference assembly there which is what is causing the issue. I'll try to investigate more but I believe that the problem is caused by some tooling inside ASP.NET.

For what is worth, I took that solution that @GSPP suggested where I was able to repro, and migrated it to use PackageReference instead of packages.config and that fixed the issue for me since I was now going through the new tooling. This is basically the advice that we have been giving to people that hits these sorts of issues. Here is the zip file after migrating the projects to package reference, @GSPP let me know if you can still repro after that:

DesignTimeBuildRepro.zip

The new PackageReference format is not possible for us to use because some packages do not support it. We are stuck with the old system for a while. A fix would be appreciated.

Is it possible to migrate to PackageReference partially? We could leave some packages in the old format.

The new PackageReference format is not possible for us to use because some packages do not support it. We are stuck with the old system for a while. A fix would be appreciated.

I'm doing some digging to see if I can figure out who is copying the wrong files into the bin folder, but it is definitely not the msbuild tooling we have for .NET Standard support. This is happening when the project loads in VS, so my gut feel is that this is part of some tooling for ASP.NET.

Is it possible to migrate to PackageReference partially? We could leave some packages in the old format.

I see. Unfortunately I don't think it's possible to be in a mixed state, you have to use either one or the other.

Ok, so after more investigating and the help from @ericstj we found that it is defintely the ASP.NET project system what is causing this issue. We also found a workaround for you without the need of migrating to PackageReference. Today, the references to some of your NuGet packages in your .csproj look like the following System.Net.Http one:

    <Reference Include="System.Net.Http, Version=4.1.1.3, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
      <HintPath>..\packages\System.Net.Http.4.3.4\lib\net46\System.Net.Http.dll</HintPath>
      <Private>True</Private>
      <Private>True</Private>
    </Reference>

What is causing this issue is those two Metadata items that say <Private>True</Private>. If you remove them you will not be able to see this issue any longer. What is happening is that when the web project is loaded, the project system will run a process (and this is not the design time build) which will do some web application specific tasks, including the call to the following method: EnsureCopyLocalAssembliesAreInBinAtFirstIdle. As its name describes, this method will try to copy the files you will need at runtime into the bin folder. The problem here, is that the System.Net.Http that you referenced in your project(the nuget package one), will be replaced with the Reference assembly from our 4.7.2 targeting pack because it has a higher assembly version, but the web project system doesn't realize that this is now the framework version, so it merges the metadata (meaning it merges the Private=True metadata in your .csproj) and copies this file (the reference assembly from our targeting pack) anyway to the bin folder. By removing the metadata from the .csproj, your project will behave properly and use the right assembly at runtime from the framework. We will chat with the folks at the web project system to see if they can come up with a fix for this.

Just to add to this, an internal ticket has been filed with the project system, so after closing it we would just need to update VS in order for this problem to go away. There is no ETA on the fix as the issue was just logged. We could also either close this issue as the problem is external to this repo, or keep it open tracking the external issue just to get updates for if/when the fix will be fixed.

Thanks! That sounds like real progress.

I'd prefer this issue to be left open as a tracking issue.

I think I am having the same problem, but this isnt a web app.

Project A - Main Project: A .NET Framework 4.7.2, WinForms application.
Project B - Referenced by project A: .NET Standard 2.0 project (Api Model)
ServiceStack - referenced by Project B

If I from Project A "use" a class from Project B (like declaring and instanciating a class from Project B), I get in runtime:

_System.IO.FileNotFoundException: 'Could not load file or assembly 'ServiceStack.Interfaces, Version=5.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.'_

So, the _ServiceStack.Interfaces_ is part of the NuGet package (actually _ServiceStack.Interfaces.Core_ hmm) referenced in Project B.

Do you guys think that is the same issue as described above? What do I then do about it? I checked the csproj-file in Project A, there is no _true_ there.

Just to add to this, an internal ticket has been filed with the project system, so after closing it we would just need to update VS in order for this problem to go away. There is no ETA on the fix as the issue was just logged. We could also either close this issue as the problem is external to this repo, or keep it open tracking the external issue just to get updates for if/when the fix will be fixed.

I have (I believe) the same problem with VS2019 (16.6.2), ASP.NET "classic" net 4.8 project and the following NuGet references: _System.Linq 4.1.0.0_, _System.Runtime.Extensions 4.1.0.0_ and _System.Runtime.InteropServices.RuntimeInformation 4.0.0.0_. The references are the transitive dependencies of the third-party library, though it's reproducible even if the mentioned NuGet packages are referenced directly. It works OK when building the project with msbuild (without VS involved), but when I open the project in VS it copies the following reference assemblies to the output directory: _System.Linq 4.1.2.0_, _System.Runtime.Extensions 4.1.2.0_, _System.Runtime.InteropServices.RuntimeInformation 4.0.2.0_ (all are from C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework.NETFramework\v4.8\Facades\ directory). The reference assemblies result in BadImageFormatException. The workaround (remove the duplicated Private=true metadata items) helps, though it would be nice to avoid the workaround as updating the third-party NuGet package adds the metadata items back. Also, switch from net48 back to net47 helps, but it can be complicated in the used large legacy solution.

@joperezr Do you have any news about the mentioned "internal ticket"? I can report this separately if you think it's another issue.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

chrisaut picture chrisaut  路  3Comments

xiedongweo picture xiedongweo  路  4Comments

ghost picture ghost  路  4Comments

KexyBiscuit picture KexyBiscuit  路  3Comments

KexyBiscuit picture KexyBiscuit  路  3Comments