Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Different behaviour of Newtonsoft.Json on .NET 5 / Core and .NET Framework

The following program results in different outcomes when run on .NET 5 (or .NET Core) and .NET Framework.

Why is the behaviour different? I'm not after the solution to the deserialisation problem; my goal here is to understand what happens.

class Versioned 
{
    public Version V {get; set;} = new Version(1,0);
}

static void Main(string[] args)
{
    // Serialised with version Newtonsoft.Json 9.0.1
    var json = "{\"V\":{\"Major\":2,\"Minor\":0,\"Build\":-1,\"Revision\":-1,\"MajorRevision\":-1,\"MinorRevision\":-1}}";

    Console.WriteLine($".NET: {System.Environment.Version}");
    Console.WriteLine($"Json.NET: {System.Reflection.Assembly.GetAssembly(typeof(Newtonsoft.Json.JsonConvert))}");

    Console.WriteLine(json);
    
    try 
    {
        var b = Newtonsoft.Json.JsonConvert.DeserializeObject<Versioned>(json);
        Console.WriteLine(b.V);
    } 
    catch (Exception ex) { Console.WriteLine(ex.GetBaseException().Message); }
}

On .NET 5: the output is (formatted for readability):

.NET: 5.0.1
Json.NET: Newtonsoft.Json, Version=11.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed
{
    "V": {
        "Major": 2,
        "Minor": 0,
        "Build": -1,
        "Revision": -1,
        "MajorRevision": -1,
        "MinorRevision": -1
    }
}

With this error:

Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Version' because the type requires a JSON string value to deserialize correctly.

To fix this error either change the JSON to a JSON string value or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List) that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object. Path 'V.Major', line 1, position 14.

On .NET Framework 4.6.2 the output is:

.NET: 4.0.30319.42000
Json.NET: Newtonsoft.Json, Version=11.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed
{
    "V": {
        "Major": 2,
        "Minor": 0,
        "Build": -1,
        "Revision": -1,
        "MajorRevision": -1,
        "MinorRevision": -1
    }
}
1.0

Additionally, with NO default value the behaviour on .NET 4.6.2 is different again.

class Versioned
{
    public Version V { get; set; }// = new Version(1, 0);
}

On .NET 5.0 the output is the same:

(...)
Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Version' because...

On .NET Framework 4.6.2 the output now is:

(...)
Version's parameters must be greater than or equal to zero.
Parameter name: build

As far as I know, the System.Version class has not changed (on the outside) between these .NET versions in a way that should play a part here (I know only of the ISpanFormattable difference). I had a peek at the source (.NET Core version and .NET Framework 4.8 version) but I cannot see anything that would explain the different behaviours.

like image 200
tymtam Avatar asked Jan 06 '21 11:01

tymtam


People also ask

Is Newtonsoft JSON compatible with .NET Core?

Text. Json library is included in the runtime for . NET Core 3.1 and later versions. For other target frameworks, install the System.

What is the difference between NET Core NET 5 and NET framework?

NET Framework is a platform for . NET applications on Windows whereas, NET Core is the latest version of the . NET Framework which is a cross-platform and open-source framework optimized for modern app needs and developer workflows.

Is .NET 5.0 Core or framework?

ASP.NET Core 5.0 is based on . NET 5 but retains the name "Core" to avoid confusing it with ASP.NET MVC 5. Likewise, Entity Framework Core 5.0 retains the name "Core" to avoid confusing it with Entity Framework 5 and 6.

Is JSON NET and Newtonsoft the same?

Thanks. Json.NET vs Newtonsoft. Json are the same thing. You must be trying to use the same code with different versions of Json.NET.


1 Answers

It looks like Json.NET got a new VersionConverter in .NET Core 2.2, which knows how to properly serialize and deserialize Version instances. This automatically gets picked up and used when you're using .NET Core 2.2+.

Using VersionConverter, Json.NET wants to serialize your Version objects to strings like "1.0", rather than to JSON objects. If you create the json string in your post by serializing a new instance of Versioned on .NET Core 2.2+:

var json = Newtonsoft.Json.JsonConvert.SerializeObject(new Versioned());

You'll see that it returns e.g. {"V":"1.0"}.

Likewise, VersionConverter only knows how to read version strings such as "1.0", and doesn't know what to do with an object containing Major, Minor, etc.

See this issue for more. See code running here.

like image 108
canton7 Avatar answered Oct 19 '22 15:10

canton7