Non-public, parameterless constructors not used for deserialization

For consistency across all supported target framework monikers (TFMs), non-public, parameterless constructors are no longer used for deserialization with JsonSerializer, by default.

Change description

The standalone System.Text.Json NuGet packages that support .NET Standard 2.0 and higher, that is, versions 4.6.0-4.7.2, behave inconsistently with the built-in behavior on .NET Core 3.0 and 3.1. On .NET Core 3.x, internal and private constructors can be used for deserialization. In the standalone packages, non-public constructors are not allowed, and a MissingMethodException is thrown if no public, parameterless constructor is defined.

Starting with .NET 5 and System.Text.Json NuGet package 5.0.0, the behavior is consistent between the NuGet package and the built-in APIs. Non-public constructors, including parameterless constructors, are ignored by the serializer by default. The serializer uses one of the following constructors for deserialization:

  • Public constructor annotated with JsonConstructorAttribute.
  • Public parameterless constructor.
  • Public parameterized constructor (if it's the only public constructor present).

If none of these constructors are available, a NotSupportedException is thrown if you attempt to deserialize the type.

Version introduced

5.0

Reason for change

  • To enforce consistent behavior between all target framework monikers (TFMs) that System.Text.Json builds for (.NET Core 3.0 and later versions and .NET Standard 2.0)
  • Because JsonSerializer shouldn't call the non-public surface area of a type, whether that's a constructor, a property, or a field.
  • If you own the type and it's feasible, make the parameterless constructor public.
  • Otherwise, implement a JsonConverter<T> for the type and control the deserialization behavior. You can call a non-public constructor from a JsonConverter<T> implementation if C# accessibility rules for that scenario allow it.

Affected APIs