5

After upgrading Application Insights to the latest version today, because our site is no longer reporting callstacks, our .NET Framework 4.6.1 ASP.NET site now crashes on initialization due to:

System.IO.FileLoadException: 'Could not load file or assembly 'System.Runtime, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)'

I have fought a very similar problem before in the past for another job. The key difference being that the issue was caused by a Nuget package pulling in .NET Core or Standard. Thus, there were multiple .NET DLLs with the same name being copied to the bin folder (System.Net.Http in that case). In that situation, it was as "easy" as never updating that Nuget package again...

Although I think the situation is slightly different here, "not upgrading" isn't an option anymore. Application Insights no longer reporting callstacks kinda defeats the purpose of the whole thing!

Since it's System.Runtime, not a Nuget package, there are no dependency version tags to nuke in the config files; although even that would have worked, that seems like a temporary solution anyway.

I theorized maybe there is now a .NET Standard of .NET Core hidden in the project somewhere, but I see no NetStandard reference, and I don't know how to tell if Core is being dragged in somehow. I have not had the pleasure (?) of working with Standard or Core yet to know more off the top of my head. I'll keep Googling...

I thought it was because we have a single .NET 3.5 DLL (with zero Nuget or DLL references besides vanilla .NET Framework 3.5's System, System.Runtime.Serialization, and System.Xml), being referenced by the ASP.NET project, though this has never been an issue before.

I am completely stumped and has stopped all development for the day. I have been upgrading and downgrading various packages, looking at their prerequisites, but I am not finding any hints.

Zoop
  • 965
  • 1
  • 13
  • 24
  • possible solution : https://stackoverflow.com/questions/45894659/fileloadexception-could-not-load-file-or-assembly-system-runtime-version-4-2-0?rq=1 – iSR5 Jul 27 '19 at 21:21
  • another : https://stackoverflow.com/questions/42755274/visual-studio-2017-could-not-load-file-or-assembly-system-runtime-version-4 – iSR5 Jul 27 '19 at 21:21
  • Regarding tags: it correctly says v4.6.1. – Zoop Jul 27 '19 at 21:29
  • Regarding clearing the bin (and obj) folder: I've done that more times than I can count. Each time the incorrect version of System.Runtime.dll will appear. – Zoop Jul 27 '19 at 21:30
  • Interestingly, I do see netstandard.dll appearing in the output folder, but no reference to netstandard in any of the project references. That supports my theory that a nuget package is pulling in netstandard. But if it's Application Insights itself, I have no clue how to resolve that because I need to upgrade Application Insights. – Zoop Jul 27 '19 at 21:33
  • I have no for System.Runtime in my app.config. Thus it cannot be confused with packages.config, which also doesn't contain a tag for System.Runtime. System.Runtime is not directly referenced by any project, according to the solution explorer. – Zoop Jul 27 '19 at 21:46
  • I have tried changing the ToolsVersion in the ASP.NET site's csproj to 15, where it was 4. I cleaned, rebuilt, and unfortunately still run into the same error. – Zoop Jul 27 '19 at 21:49
  • I have tried upgrading to Visual Studio 2019 from 2017, and nothing changed. – Zoop Jul 27 '19 at 22:54
  • I see various warnings regarding `Consider app.config remapping of assembly System.Runtime`, but I am not sure what that means. I set my build log to detailed, but it says the same thing I already knew: there are multiple versions of System.Runtime around. It seems like everyone wants a different version. I tried adding System.Runtime from Nuget and then using tags to use the latest version, but now I get multiple FileNotFoundExceptions, one for version 4.2.0.0 and one for version 4.0.20.0! They're multiplying! – Zoop Jul 27 '19 at 22:56
  • What I really need is a "use this version no matter what" ability. That's what I thought did, but given that I am now facing distinct errors for various versions, I am at a loss. – Zoop Jul 27 '19 at 23:01
  • Supposed PackageReference, instead of packages.config, could solve the issue, but PackageReference isn't supported by ASP.NET projects.... – Zoop Jul 27 '19 at 23:31
  • I am now looking into updating to .NET Core, which seems like a GIGANTIC undertaking just to have callstacks and no more DLL Hell... – Zoop Jul 27 '19 at 23:48
  • not sure, but you might be able to trace the error by changing the MSBuild to detailed `Tools > Options > Projects and Solutions > Build and Run ` then change MSBuild to Detailed. Next, rebuild the solution, you'll see more detailed logs. – iSR5 Jul 27 '19 at 23:50
  • instead of updating to .NET Core, you could try change .net framework to a higher version. – iSR5 Jul 27 '19 at 23:52
  • Yes, I have already set the build output to detailed, and I do see that it's struggling to pick versions, but I am not sure how that helps me. I already know it doesn't know which version to pick. I don't know how to tell it which version to use. I am certain that if it simply used the latest version in all situations, it'd be fine. – Zoop Jul 27 '19 at 23:59
  • I have already set the projects to .NET Framework 4.7.2 and I still get the same errors. – Zoop Jul 28 '19 at 00:00
  • this would give you an idea on how to tell it which version to use : https://michaelscodingspot.com/how-to-resolve-net-reference-and-nuget-package-version-conflicts/ – iSR5 Jul 28 '19 at 00:05
  • Yes, updating to .NET Core seems unfeasible at this time. It looks like it'd take a major refactor to accomplish it. So I'm back to square one: somewhere, somehow, at least two versions of System.Runtime versions are required, and I have no way to force them to all use the same version. – Zoop Jul 28 '19 at 00:05
  • Modules window doesn't show System.Runtime.dll at all, so I'm guessing that means it's not loaded at all? – Zoop Jul 28 '19 at 00:12
  • It appears adding simply makes it not load System.Runtime at all. That's why I get two file not found errors instead of one when I use it. – Zoop Jul 28 '19 at 00:16
  • The versions displayed after adding System.Runtime as a nuget package makes no sense at all. Nuget package manager reports version 4.3.1. The solution explorer says it's getting it from `Reference Assemblies\...\v4.7.2\...`, instead of the packages folder. The CSPROJ says it's version 4.1.1.1 from `packages\System.Runtime.4.3.1`, where I'd expected it to be from. The file copied to the bin folder says its version 4.7.3061.0. I am guessing the 4.7.X numbers may be a reference to .NET Framework version? But it still doesn't make any sense. – Zoop Jul 28 '19 at 00:22
  • have you tried to uninstall it from nuguts then reinstall it? – iSR5 Jul 28 '19 at 00:25
  • I previously had no nugets of System.Runtime. I only added it after I started getting the file not found errors. And yes, I've reinstalled it numerous times. – Zoop Jul 28 '19 at 00:26
  • try to create a new empty .NET Core solution, and then reassemble it from the corrupted one. – iSR5 Jul 28 '19 at 00:32
  • It wasn't a .NET Core project from the beginning. It was .NET 4.6.1. I ran the portability tool and about 14% of the project would require rewriting. That'd take days. – Zoop Jul 28 '19 at 00:37
  • Well I may have narrowed down the dependency path: System.Runtime.4.3.1 > System.Security.Cryptography.Algorithms.4.3.1 > System.Security.Cryptography.X509Certificates.4.3.2 > System.Net.Http.4.3.4 > Used by just about everyone. Funnily enough, System.Net.Http was the Nuget at my other job that we simply had to avoid because of this very same problem! – Zoop Jul 28 '19 at 00:57
  • The problem boils down to, despite having the Nuget package, Visual Studio will always prefer the GACed DLL. – Zoop Jul 28 '19 at 00:59
  • Even if I force Visual Studio to use a handpicked version of System.Runtime.dll, then use to point to that version, it will then say file not found to both the handpicked version of 4.1.2.0 and 4.0.20.0. The inner exceptions indicate that System.Runtime 4.1.2.0 has a dependency upon 4.0.20.0!?! – Zoop Jul 28 '19 at 01:04
  • I got it to run, but I don't have a solution. I grabbed a random instance of System.Runtime.dll from dotnet\sdk, looked up the version in ILSpy, manually copied it into the bin folder, and set the to point to that version. So now I need to get Visual Studio to copy the right DLL for me. – Zoop Jul 28 '19 at 01:17

1 Answers1

6

Two different Nugets want to pull in different versions of System.Runtime.dll. This is extremely common in a .NET project using Nugets that use .NET Standard. This is now the second time I've run into this problem stemming from System.Net.Http, because it's used by just about everyone.

Since System.Runtime is a .NET Framework DLL, Visual Studio will always grab it from the Program Files\Reference Assemblies folder, no matter what you do in Visual Studio or the CSProj.

In my case, for whatever reason, the version being copied to the bin folder was a reflection-only version of the desired DLL, meaning I could not simply use a <dependantAssembly> tag to force it to use the version that was in the bin folder. I had to first get a full-fledged version of System.Runtime.dll into the bin folder.

Short of updating to .NET Core, the only other idea I had (and confirmed by another Stack Overflow user) was to copy it over by hand in a post-build. It's awful, but it works with whatever conflicted DLL you have:

  1. You will likely have the conflicted DLL in your project's references, due to the Nuget package. My issue was harder because although System.Runtime is a prerequisite to another Nuget I was using, I guess because it's part of .NET Framework, it wasn't added as a Nuget package or a reference. If not, go pull the Nuget package yourself.
  2. Look up the path to the DLL in your packages folder. For example, mine was $(SolutionDir)packages\System.Runtime.4.3.1\lib\net462\System.Runtime.dll. You will want to swap your solution directory with the $(SolutionDir) macro, as I did.
  3. Edit your post build event command line in your project's solution properties:

    copy "$(SolutionDir)packages\System.Runtime.4.3.1\lib\net462\System.Runtime.dll" "$(TargetDir)System.Runtime.dll"

  4. Open the DLL in something that can see its version number and public key token, like ILSpy. In my case, the DLL is version 4.1.1.1 with public key token b03f5f7f11d50a3a. Note, viewing the DLL's properties in File Explorer does NOT show you the right version number.

  5. Open your app.config/web.config in a text editor. If you do not already have a <dependentAssembly> tag for your DLL in the configuration\runtime\assemblyBinding tag, add it. It should look something like this:

<dependentAssembly> <assemblyIdentity name="System.Runtime" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/> <bindingRedirect oldVersion="0.0.0.0-9.9.9.9" newVersion="4.1.1.1"/> </dependentAssembly>

  1. (continued) Replace the name with the DLL's file name without the .DLL extension. Replace the public key token with the value you discovered in ILSpy. Set oldVersion to a wide range. Set newVersion to be the version you found in ILSpy.
  2. Whenever you touch that nuget package in Nuget Package Manager, it may change your <dependentAssembly> tag! So, leave a text file, a sticky note, a neon-lit sign on your project, saying that if you ever mess with that Nuget package, you may need to edit the post-build and app.config/web.config.
  3. Cry.

If you're stuck on .NET Framework like I am, you may end up having to do this hack on many DLLs, as .NET Standard/Core become more pervasive, and thus more DLLs end up with the same name as their .NET Framework counterparts. We found that deploying this solution onto Azure did NOT work.

Otherwise, the only other solution is to avoid it altogether: upgrade only one Nuget package at a time and test thoroughly after each time. Nuget can be like Russian Roulette ;-). Although the above worked for us, we ended up rolling back and slowly and painfully upgrade until we found the culprits.

If you know a better way, I'd love to hear it.

Zoop
  • 965
  • 1
  • 13
  • 24
  • 2
    Removing all binding .NET Framework dependentAssembly bindingRedirects from web.config worked for me, no need to have the dll at all in bin – rfcdejong Oct 20 '20 at 08:40
  • Removing dependent assembly in web.config worked for me too. – Matt Nov 12 '21 at 19:21