Could not load file or assembly System.Runtime in NET4x

21 Mar 2021

This is the most common issue that happens in DotNet world as more legacy NET4x (.NET 4.0 or 4.5) projects or dependent packages are upgraded to NET47 or NET48. Though this issue was more prevalent and spread across multiple GitHub discussion threads, the solution wasn't directly mentioned in most discussion threads. So, I'm just going to record what I've gone through and the final fix that worked for me.

While working on a recent task, I wanted to include latest version of Autofac library and upgrade few other dependent libraries. So, I have upgraded my .NET framework to NET 4.7.2.

Upgrade went smoothly as expected and the application started to work fine. but, when I tried to run few unit tests for my class library project, the testrunner failed to identify the unit tests.

The log showed following error

WARN TestRunner: Discoverer [MSTest][Discovery][D:\Projects\xxx\yyyy.UnitTests\bin\Debug\yyyy.Tests.dll] Failed to discover tests from assembly D:\Projects\xxx\yyyy.UnitTests\bin\Debug\yyyy.Tests.dll. 
Reason:Could not load file or assembly 'System.Runtime, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The system cannot find the file specified. 

I've initially thought that it was yet another simple assembly reference issue, that resulted in missing DLL within bin folder.

Try 1:

I found reference to System.Runtime in csproj and tried to play with the available properties.

  1. changed Copy Local,
  2. changed to use Specific version
  3. removed reference and installed System.Runtime nuget package
  4. removed reference and added it from the framework folder C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\Facades\
  5. tried changing assembly redirects in app.config first matching with nuget package and later with .NET 4.7.2 facade dll
  6. tried adding in assembly reference within compilation tag in config file

Nothing could bring System.Runtime back in the unit test projects bin folder. Browsing through various threads, confirmed that System.Runtime will be dynamically referred from the GAC and the project doesn't need to worry for latest frameworks.

Try 2:

I tried to diagonise underlying cause using

  1. Fusion Log viewer for identifying assembly binding issue
  2. Enabled msbuild log and was going through cryptic texts captured in log file

All that information didn't lead me to any sign of obvious errors,.. that I can fix.

Try 3:

I blamed visual studio IDE and NuGet package manager for not being able to bring a simple DLL into bin folder. In one of the StackOverflow discussion, a guy specified a fix using post build event that executes and copies "System.Runtime" dll into Bin folder. So, I made my mind that it has to be old school way of maintaining dll within the project folder and refer it right from there.

This way, I was able to successfully force Visual Studio to output System.Runtime.dll into bin folder. But the unit tests didn't run as expected and something is still wrong under the hood.

Try 4:

While looking at few discussions, I saw mention about PCL (Portable Class Libraries) and the need to use Microsoft.Bcl.Build package that can work-around the limitations of legacy "packages.config" and bring back missing assemblies for local development. I started to add it to the class library and the unit test project. Hoped that it would solve the problem.

Still no success and it added few more complexity to add BCL classes to all the dependent projects

Try 5:

After going through discussions on limitations of packages.config, and the need to migrate old system to latest PackageReferences. Few GitHub thread gave promising words that it would solve all reference issue.

With all my hopes high, I migrated the class libraries to use PackageReferences. After my first build, I was shocked to see that BCL package complaining about missing packages.config file.

Now, a new problem to understand!

BCL packages was introduced to bring back few new build requirements to the legacy Nuget system using package.config. So, people can use latest libraries without upgrading the NET4x (<.NET 4.6) projects. So, I went back removing all Microsoft.BCL.Build packages and the error message went away. But still after a successful build, this promising change didn't fix my unit test execution issue.

Solution:

Rather than searching for solutions, I've started to look into all discussion threads for underlying reason on how this issue was introduced which affects whole lot of developers on NET4x frameworks. While browsing through, I saw a simple reply from github user that was not even acknowledged as a working solution but worked great!

Root cause was due to packages written in .NETStandard and .NET Framework mixed up during builds and causing various irrelated symptoms (wrong assembly redirects, missing indirect assembly references etc.., ).

In web application project, visual studio promptly suggests us to refer netstandard library when a nuget package written in .NETStandard is referred. But coming to class library, it doesn't suggest you to add reference to netstandard package causing whole lot of problem with the unit tests.

I went ahead and installed netstandard package to the unit test project as suggested in this GitHub issue. That resolved my problem!!

Still no System.Runtime dll in BIN folder, but everything works without being in there.

In addition...
When you see missing assemblies - try to remove all the assembly redirects from app.config and add them one by one based on the errors that you see. Because the redirects added for old framework assemblies/version can be a huge problem creator for upgrades. 

Hope this article saves your time.

Related Posts