Skip to content

[Breaking change]: JsonSerializerOptions copy constructor now includes JsonSerializerContext #30756

@eiriktsarpalis

Description

@eiriktsarpalis

Description

With the release of source generation in .NET 6 the JsonSerializerOptions copy constructor was intentionally made to ignore its JsonSerializerContext state (see also dotnet/aspnetcore#38720). This made sense at the time since JsonSerializerContext was designed to have a 1:1 relationship with JsonSerializerOptions instances. The introduction of dotnet/runtime#63686 generalizes and replaces JsonSerializerContext with IJsonTypeInfoResolver, which removes the need for such tight coupling.

We have updated the copy constructor to include the IJsonTypeInfoResolver/JsonSerializerContext information, which could manifest as a breaking change for certain .NET 6 scenaria.

Version

.NET 7 Preview 7

Previous behavior

In .NET 6, the code

var options = new JsonSerializerOptions(MyContext.Default.Options);
JsonSerializer.Serialize(new Poco2(), options);

[JsonSerializable(typeof(Poco1))]
public partial class MyContext : JsonSerializerContext {}

public class Poco1 {}
public class Poco2 {}

serializes successfully since the MyContext configuration (which doesn't support Poco2) is discarded by the copy constructor -- serialization succeeds because the new options instance defaults to using reflection-based serialization.

New behavior

The same code now throws InvalidOperationException, since the copy constructor now incorporates MyContext metadata which does not support Poco2 contracts.

Type of breaking change

  • Binary incompatible: Existing binaries may encounter a breaking change in behavior, such as failure to load/execute or different run-time behavior.
  • Source incompatible: Source code may encounter a breaking change in behavior when targeting the new runtime/component/SDK, such as compile errors or different run-time behavior.

Reason for change

JsonSerializerContext was the only setting ignored by the copy constructor, which was surprising behavior for certain users.

Recommended action

Users depending on .NET 6 behavior can now manually unset the TypeInfoResolver property to get back reflection-based contract resolution:

var options = new JsonSerializerOptions(MyContext.Default.Options);
options.TypeInfoResolver = null; // unset `MyContext.Default` as the resolver for the options instance.

Feature area

Core .NET libraries

Affected APIs

No response

Metadata

Metadata

Assignees

Labels

🏁 Release: .NET 7Work items for the .NET 7 releasebinary incompatibleExisting binaries may encounter a breaking change in behavior.breaking-changeIndicates a .NET Core breaking change

Type

No type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions