Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
328 views
in Technique[技术] by (71.8m points)

c# - 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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...