Search code examples
c#mstest.net-4.8system.text.jsonjson-serialization

System.Text.Json throws TypeInitializationException in .NET framework unit tests


I have created a (fresh) solution in Visual Studio 2022 17.12.4 with the following projects:

  • ClassLibrary1 (.NET framework 4.8)
    • Has System.Text.Json installed version 9.0.1
    • Has a static method Just.DoIt that calls JsonSerializer.Serialize()
  • ConsoleApp1 (.NET framework 4.8)
    • Has a reference to ClassLibrary1
    • Calls static method Just.DoIt
  • WpfApp1 (.NET framework 4.8)
    • Has a reference to ClassLibrary1
    • Calls static method Just.DoIt
  • UnitTests1 (.NET framework 4.8)
    • Has a reference to ClassLibrary1
    • Calls static method Just.DoIt in a unit test

Here's the Just.DoIt code:

public static class Just
{
    public static void DoIt()
    {
        var person = new Person { FirstName = "Jan", Age = 37, };
        Console.WriteLine(person.ToString());
        string json = JsonSerializer.Serialize(person);
        Console.WriteLine(json);
        var person2 = JsonSerializer.Deserialize<Person>(json);
        Console.WriteLine(person2.ToString());
    }
}

public class Person
{
    [JsonPropertyName("age")]
    public int Age { get; set; }
    [JsonPropertyName("firstname")]
    public string FirstName { get; set; }
    public override string ToString() { return $"{FirstName} ({Age})"; }
}

The console app and wpf app work fine, but the unit test throws an exception when reaching the JsonSerializer.Serialize():

Test method UnitTests1.JustDoItTest.TestMethod1 threw exception: 
System.TypeInitializationException: The type initializer for 'System.Text.Json.JsonSerializer' threw an exception. ---> System.TypeInitializationException: The type initializer for 'PerTypeValues`1' threw an exception. ---> System.IO.FileNotFoundException: Could not load file or assembly 'System.Runtime.CompilerServices.Unsafe, Version=4.0.4.1, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The system cannot find the file specified.

I have tried the following things that did not solve the issue:

  • Installing System.Runtime.CompilerServices.Unsafe 6.1.0 in every project
  • Creating an App.config with binding redirects in every project.
<dependentAssembly>
    <assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
    <bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
</dependentAssembly>

and also:

<dependentAssembly>
    <assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
    <bindingRedirect oldVersion="0.0.0.0-6.1.0.0" newVersion="6.1.0.0" />
</dependentAssembly>
  • Running the tests outside Visual Studio with dotnet test.
  • Adding <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies> to the unit tests .csproj file.
  • Updated MSTest.TestFramework and MSTest.TestAdapter from 2.2.10 to 3.7.1.
  • Installed Microsoft.TestPlatform in the unit tests project.
  • All the normal steps, like: clean, rebuild, restore and restart Visual Studio.

Do you know how I can solve this issue and not get the exception in the unit test project?


Solution

  • I've been trying to solve this issue for 2 days now and now that I've posted the question I found a solution :$

    stackoverflow.com/a/73557076/12924241 Inspired me to change the bindingRedirect to the correct version (6.0.1.0).

    This is the correct App.config with binding redirects:

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <runtime>
        <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
          <!--
            This binding redirect is needed to make anything that involves calling System.Text.Json to work.
            For some reason this is only needed in unit test projects.
          -->
          <dependentAssembly>
            <assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
            <bindingRedirect oldVersion="0.0.0.0-6.0.1.0" newVersion="6.0.1.0" />
          </dependentAssembly>
        </assemblyBinding>
      </runtime>
    </configuration>