Newtonsoft.json: Upgrade to .NET Core 3.1 broke serialization of System.Version.

Created on 20 Dec 2019  ·  4Comments  ·  Source: JamesNK/Newtonsoft.Json

We are in the process of upgrading from .NET Core 2.2 to 3.1 and I noticed that we were getting serialization failures during testing. Looking into it, it was blowing up from trying to deserialize data coming from Elasticsearch that contained System.Version. I'm trying to track this down and will provide more information as I find it. I just wanted to get the ball rolling.

I also realize that there is a ton of test coverage already on System.Version. I just find it crazy (and thinking to myself that I'm going crazy) that we have no defined converters (like the VersionConverter in registered in our converter list) and we are using JSON.NET 12.0.(2|3) and the only change was the runtime which updated the BCL types. I totally get that creating a new type below can and would bypass any specific type checks inside of JSON.NET. But I'd expect to work the same across runtimes.

Source/destination types

        public class TestModel {
            public System.Version Version { get; set; }
            public System.Version2 Version2 { get; set; }
        }

serialized JSON

{"Version":"1.0","Version2":{"Major":1,"Minor":0,"Build":-1,"Revision":-1,"MajorRevision":-1,"MinorRevision":-1}}

Expected behavior


I'd expect it to output the previous json for sake of backwards compatibility or provide a converter so we get a normalized output. I only found this because Elasticsearch was blowing up trying to deserialize these models after we upgraded to .net core 3.1 from 2.2

Link to current source for .NET Core 3.x System.Version
https://github.com/dotnet/corefx/blame/master/src/Common/src/CoreLib/System/Version.cs
Link to previous 2.2 System.Version:
https://github.com/dotnet/corefx/blob/b3efd32a0c529240ce520839e28031d8beb84b85/src/Common/src/CoreLib/System/Version.cs

I looked at the source and compared the two, it's basically all just basic newer language feature changes like null reference types, expression bodies.

Versions were previously outputted as

{"Major":1,"Minor":0,"Build":-1,"Revision":-1,"MajorRevision":-1,"MinorRevision":-1}

Current:

"1.0"

Actual behavior

{"Version":"1.0","Version2":{"Major":1,"Minor":0,"Build":-1,"Revision":-1,"MajorRevision":-1,"MinorRevision":-1}}

Steps to reproduce

You can use the model above or you can run this with just the version field in a 2.2 console app and then change it to 3.1 should do the trick as well.

For Version2 type just copy the latest 2.2 corefx version of System.Version located here or get it from my gist here with minimal edits so it compiles.

            var model = new TestModel {
                Version = new Version(1, 0),
                Version2 = new Version2(1, 0)
            };

            string json = JsonConvert.SerializeObject(model, new JsonSerializerSettings());

Most helpful comment

Thanks for the reply. That was my first thought but then I didn't see a type converter on the Version class itself. Pretty sweet how there is not a type converter class directly on Version / any reference/documentation stating how it will be affected. I didn't even see a change log that states this behavior that I've seen and this is up there on breaking changes (changing how serialization happens to a type). I even searched GitHub but didn't see anything. Took digging through the issues and not the C# find results on GitHub (of which there was none) to find it.

Thanks again!

reference:
https://github.com/dotnet/corefx/pull/28516/files

All 4 comments

.NET Core 3 has a TypeConverter for Version: VersionConverter. Newtonsoft.Json automatically picks it up from TypeDescriptor.GetConverter(typeof(Version)).

You could write a JsonConverter to explicitly control how Version is serialized.

Thanks for the reply. That was my first thought but then I didn't see a type converter on the Version class itself. Pretty sweet how there is not a type converter class directly on Version / any reference/documentation stating how it will be affected. I didn't even see a change log that states this behavior that I've seen and this is up there on breaking changes (changing how serialization happens to a type). I even searched GitHub but didn't see anything. Took digging through the issues and not the C# find results on GitHub (of which there was none) to find it.

Thanks again!

reference:
https://github.com/dotnet/corefx/pull/28516/files

Same problem here. Hate that this is practically unfindable. Nothing in the changelogs.

How could this not work:

var json = JsonConvert.SerializeObject(new Version(1, 2, 3, 4));
var x = JsonConvert.DeserializeObject<Version>(json, new VersionConverter());  //CRASH

Very simple example of code screwup guys... please fix it

Thanks for the reply. That was my first thought but then I didn't see a type converter on the Version class itself. Pretty sweet how there is not a type converter class directly on Version / any reference/documentation stating how it will be affected. I didn't even see a change log that states this behavior that I've seen and this is up there on breaking changes (changing how serialization happens to a type). I even searched GitHub but didn't see anything. Took digging through the issues and not the C# find results on GitHub (of which there was none) to find it.

Thanks again!

reference:
https://github.com/dotnet/corefx/pull/28516/files

I also faced lot of issues due to this breaking change. I am surprised as to why this is no where mentioned in the change logs.

Was this page helpful?
0 / 5 - 0 ratings