Skip to content

TimeSpan serialization breaking change #27655

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

Merged
merged 5 commits into from
Jan 12, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/core/compatibility/6.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ If you're migrating an app to .NET 6, the breaking changes listed here might aff

| Title | Binary compatible | Source compatible | Introduced |
| - | - | - | - |
| [Default serialization format for TimeSpan](serialization/6.0/timespan-serialization-format.md) | ❌ | ✔️ | Servicing 6.0.2 |
| [IAsyncEnumerable serialization](serialization/6.0/iasyncenumerable-serialization.md) | ✔️ | ❌ | Preview 4 |
| [JSON source-generation API refactoring](serialization/6.0/json-source-gen-api-refactor.md) | ❌ | ✔️ | RC 2 |
| [JsonNumberHandlingAttribute on collection properties](serialization/6.0/jsonnumberhandlingattribute-behavior.md) | ❌ | ✔️ | RC 1 |
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
---
title: "Breaking change: Default serialization format for TimeSpan"
description: Learn about the .NET 6 servicing release breaking change where the default serialization format for TimeSpan in source generators has changed.
ms.date: 01/11/2022
---
# Default serialization format for TimeSpan

<xref:System.Text.Json?displayProperty=fullName> added support for <xref:System.TimeSpan> in .NET 6 GA, however this change did not include support for source generators. In .NET 6 servicing release 6.0.2, <xref:System.Text.Json?displayProperty=fullName> includes support for source-generator serialization of <xref:System.TimeSpan> values. This support changes the default serialization format for <xref:System.TimeSpan> values in source generators.

## Previous behavior

In .NET 6 GA, source generators serialize <xref:System.TimeSpan> values by outputting all public properties of the type, which is the default serialization behavior for objects:

```json
{"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}
```

## New behavior

In servicing release .NET 6.0.2, source generators serialize <xref:System.TimeSpan> values in the following format, which is consistent with the reflection-based serializer format:

```json
"00:00:01"
```

## Version introduced

.NET 6.0.2 (servicing release)

## Type of breaking change

This change may affect [binary compatibility](../../categories.md#binary-compatibility).

## Reason for change

[System.Text.Json source generation](../../../../standard/serialization/system-text-json-source-generation.md) is a new feature, and its serialization behavior should be as consistent as possible with the reflection-based serializer. This change simplifies migration to source generators.

## Recommended action

It's unlikely for users to depend on the current <xref:System.TimeSpan> serialization format, as it redundantly outputs all public properties of the type (which is the default serialization behavior for objects), and it doesn't roundtrip.

If you do depend on the existing behavior, the recommended course of action is to [author a custom converter](../../../../standard/serialization/system-text-json-converters-how-to.md) that outputs the needed properties from <xref:System.TimeSpan>:

```csharp
public class TimeSpanConverter : JsonConverter<TimeSpan>
{
public void WriteValue(Utf8JsonWriter writer, TimeSpan value, JsonSerializerOptions options)
{
writer.WriteStartObject();
writer.WriteNumber("days", value.Days);
writer.WriteNumber("hours", value.Hours);
/* insert any needed properties here */
writer.WriteEndObject();
}
}
```

## Affected APIs

- <xref:System.Text.Json.JsonSerializer.Serialize%2A?displayProperty=fullName>

## See also

- [How to use source generation in System.Text.Json](../../../../standard/serialization/system-text-json-source-generation.md)
4 changes: 4 additions & 0 deletions docs/core/compatibility/toc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,8 @@ items:
href: sdk/6.0/runtimeidentifier-self-contained.md
- name: Serialization
items:
- name: Default serialization format for TimeSpan
href: serialization/6.0/timespan-serialization-format.md
- name: IAsyncEnumerable serialization
href: serialization/6.0/iasyncenumerable-serialization.md
- name: JSON source-generation API refactoring
Expand Down Expand Up @@ -901,6 +903,8 @@ items:
items:
- name: .NET 6
items:
- name: Default serialization format for TimeSpan
href: serialization/6.0/timespan-serialization-format.md
- name: IAsyncEnumerable serialization
href: serialization/6.0/iasyncenumerable-serialization.md
- name: JSON source-generation API refactoring
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ The following sections provide converter samples that address some common scenar
* [Deserialize inferred types to object properties](#deserialize-inferred-types-to-object-properties).
* [Support polymorphic deserialization](#support-polymorphic-deserialization).
* [Support round-trip for Stack\<T>](#support-round-trip-for-stackt).
* [Support enum string value deserialization](#support-enum-string-value-deserialization)
* [Support enum string value deserialization](#support-enum-string-value-deserialization).
::: zone-end

::: zone pivot="dotnet-core-3-1"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,8 @@ Here are the preceding examples in a complete program:

You can specify metadata collection mode or serialization optimization mode for an entire context, which may include multiple types. Or you can specify the mode for an individual type. If you do both, the mode specification for a type wins.

* For an entire context, use the [`GenerationMode`](https://github.com/dotnet/runtime/blob/a85d36fed49b8c56d3365417e047fc4306cd74fc/src/libraries/System.Text.Json/Common/JsonSourceGenerationOptionsAttribute.cs#L53-L56) property of `JsonSourceGenerationOptionsAttribute`.
* For an individual type, use the <xref:System.Text.Json.Serialization.JsonSerializableAttribute.GenerationMode> property of <xref:System.Text.Json.Serialization.JsonSerializableAttribute>.
* For an entire context, use the <xref:System.Text.Json.Serialization.JsonSourceGenerationOptionsAttribute.GenerationMode?displayProperty=nameWithType> property.
* For an individual type, use the <xref:System.Text.Json.Serialization.JsonSerializableAttribute.GenerationMode?displayProperty=nameWithType> property.

### Serialization optimization mode example

Expand Down Expand Up @@ -113,7 +113,7 @@ You can specify metadata collection mode or serialization optimization mode for

## Specify options for serialization optimization mode

Use [`JsonSourceGenerationOptionsAttribute`](https://github.com/dotnet/runtime/blob/a85d36fed49b8c56d3365417e047fc4306cd74fc/src/libraries/System.Text.Json/Common/JsonSourceGenerationOptionsAttribute.cs) to specify options that are supported by serialization optimization mode. You can use these options without causing a fallback to `JsonSerializer` code. For example, `WriteIndented` and `CamelCase` are supported:
Use <xref:System.Text.Json.Serialization.JsonSourceGenerationOptionsAttribute> to specify options that are supported by serialization optimization mode. You can use these options without causing a fallback to `JsonSerializer` code. For example, `WriteIndented` and `CamelCase` are supported:

:::code language="csharp" source="snippets/system-text-json-source-generation/csharp/SerializeOnlyWithOptions.cs" id="JsonSourceGenerationOptions":::

Expand Down