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.
Text. Json library is included in the runtime for . NET Core 3.1 and later versions. For other target frameworks, install the System.
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.
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With