-
Notifications
You must be signed in to change notification settings - Fork 4.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
TimeSpan is (de)serialized incorrectly using the JSON source generator #62082
Comments
Tagging subscribers to this area: @dotnet/area-system-text-json Issue DetailsDescriptionIf a {"duration":{"days":0,"hours":0,"milliseconds":0,"minutes":0,"seconds":1,"ticks":10000000,"totalDays":1.1574074074074073E-05,"totalHours":0.0002777777777777778,"totalMilliseconds":1000,"totalMinutes":0.016666666666666666,"totalSeconds":1}} If a {"duration":"00:00:01"} Similarly, the source generator will fail to deserialize strings to Curiously, if the instance of Reproduction StepsTo reproduce run using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
var value = new MyObject { Duration = TimeSpan.FromSeconds(1) };
var context = new MyJsonContext(new(JsonSerializerDefaults.Web));
var options = new JsonSerializerOptions(JsonSerializerDefaults.Web);
// Outputs the TimeSpan as an object
var bytes = JsonSerializer.SerializeToUtf8Bytes(value, typeof(MyObject), context);
var json = Encoding.UTF8.GetString(bytes);
Console.WriteLine(json);
Console.WriteLine();
// Outputs the TimeSpan as a string
bytes = JsonSerializer.SerializeToUtf8Bytes<MyObject>(value, options);
json = Encoding.UTF8.GetString(bytes);
Console.WriteLine(json);
Console.WriteLine();
options = new JsonSerializerOptions(JsonSerializerDefaults.Web);
// Create a new context that uses the same options.
// This causes the behavior of SerializeToUtf8Bytes<T>() to change.
context = new MyJsonContext(options);
// Outputs the TimeSpan as an object again
bytes = JsonSerializer.SerializeToUtf8Bytes<MyObject>(value, options);
json = Encoding.UTF8.GetString(bytes);
Console.WriteLine(json);
Console.WriteLine();
try
{
JsonSerializer.Deserialize<MyObject>("{\"duration\":\"00:00:01\"}", options);
}
catch (JsonException ex)
{
Console.Error.WriteLine("Failed to deserialize TimeSpan from string: {0}", ex);
Console.Error.WriteLine();
}
[JsonSerializable(typeof(MyObject))]
public partial class MyJsonContext : JsonSerializerContext
{
}
public class MyObject
{
public TimeSpan Duration { get; set; }
} <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<ImplicitUsings>enable</ImplicitUsings>
<NoWarn>$(NoWarn);CA1050</NoWarn>
<Nullable>enable</Nullable>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
</PropertyGroup>
</Project> Expected behaviorThe application outputs the following: {"duration":"00:00:01"}
{"duration":"00:00:01"}
{"duration":"00:00:01"} Actual behaviorThe application outputs the following: {"duration":{"days":0,"hours":0,"milliseconds":0,"minutes":0,"seconds":1,"ticks":10000000,"totalDays":1.1574074074074073E-05,"totalHours":0.0002777777777777778,"totalMilliseconds":1000,"totalMinutes":0.016666666666666666,"totalSeconds":1}}
{"duration":"00:00:01"}
{"duration":{"days":0,"hours":0,"milliseconds":0,"minutes":0,"seconds":1,"ticks":10000000,"totalDays":1.1574074074074073E-05,"totalHours":0.0002777777777777778,"totalMilliseconds":1000,"totalMinutes":0.016666666666666666,"totalSeconds":1}}
Failed to deserialize TimeSpan from string: System.Text.Json.JsonException: The JSON value could not be converted to System.TimeSpan. Path: $.duration | LineNumber: 0 | BytePositionInLine: 22.
at System.Text.Json.ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(Type propertyType)
at System.Text.Json.Serialization.Converters.ObjectDefaultConverter`1.OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
at System.Text.Json.Serialization.Converters.JsonMetadataServicesConverter`1.OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
at System.Text.Json.Serialization.JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
at System.Text.Json.Serialization.Metadata.JsonPropertyInfo`1.ReadJsonAndSetMember(Object obj, ReadStack& state, Utf8JsonReader& reader)
at System.Text.Json.Serialization.Converters.ObjectDefaultConverter`1.OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
at System.Text.Json.Serialization.Converters.JsonMetadataServicesConverter`1.OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
at System.Text.Json.Serialization.JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
at System.Text.Json.Serialization.JsonConverter`1.ReadCore(Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state)
at System.Text.Json.JsonSerializer.ReadFromSpan[TValue](ReadOnlySpan`1 utf8Json, JsonTypeInfo jsonTypeInfo, Nullable`1 actualByteCount)
at System.Text.Json.JsonSerializer.ReadFromSpan[TValue](ReadOnlySpan`1 json, JsonTypeInfo jsonTypeInfo)
at System.Text.Json.JsonSerializer.Deserialize[TValue](String json, JsonSerializerOptions options)
at Program.<Main>$(String[] args) in C:\Coding\martincostello\JsonSourceGeneratorObsoleteProperties\Program.cs:line 39 Regression?No. Known WorkaroundsNo response ConfigurationPartial output from > dotnet --info
.NET SDK (reflecting any global.json):
Version: 6.0.100
Commit: 9e8b04bbff
Runtime Environment:
OS Name: Windows
OS Version: 10.0.19043
OS Platform: Windows
RID: win10-x64
Base Path: C:\Program Files\dotnet\sdk\6.0.100\
Host (useful for support):
Version: 6.0.0
Commit: 4822e3c3aa Other informationNo response
|
My (clearly biased) opinion is that this would be a good candidate for servicing as the built-in I'm still testing out the JSON source generator in an internal app (which is where these issues have been surfaced), and for the app using |
Description
If a
TimeSpan
is serialized using the JSON source generator it is output as an object:If a
TimeSpan
is serialized without using the source generator, it is serialized as a string:Similarly, the source generator will fail to deserialize strings to
TimeSpan
values as it is expecting an object.Curiously, if the instance of
JsonSerializerOptions
used to serialize as astring
is passed to a new instance of the custom JSON serializer context but then not used, then same operation will then change to serializing as an object from a string.Reproduction Steps
To reproduce run
dotnet build
using the .NET 6.0.100 SDK for the below application.Expected behavior
The application outputs the following:
Actual behavior
The application outputs the following:
Regression?
No.
Known Workarounds
No response
Configuration
Partial output from
dotnet --info
:Other information
No response
The text was updated successfully, but these errors were encountered: