-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Description
Background and Motivation
Even though we have covered the blocking issue of not being able to (de)serialize reference loops (#30820, #29900) by adding ReferenceHandler.Preserve to S.T.Json, there is many asks for adding an option equivalent to Json.NET's ReferenceLoopHandling.Ignore.
Motivations for doing this are:
ReferenceHandler.Preservemay be too cumbersome and increases payload size.ReferenceHandler.Preservecreates JSON incomprehensible by serializers other than S.T.Json and Json.NET.
Proposed API
namespace System.Text.Json.Serialization
{
public abstract partial class ReferenceHandler
{
public static ReferenceHandler Preserve { get; }
+ public static ReferenceHandler IgnoreCycle { get; }
}
}Usage Examples
class Node
{
public string Description { get; set; }
public Node Next { get; set; }
}
void Test()
{
var node = new Node { Description = "Node 1" };
node.Next = node;
var opts = new JsonSerializerOptions { ReferenceHandler = ReferenceHandler.IgnoreCycle };
string json = JsonSerializer.Serialize(node, opts);
Console.WriteLine(json); // Prints: {"Description":"Node 1"}.
// Note property "Next" being ignored due to cycle detection.
}Alternative Designs
This new API is being added to ReferenceHandler class since this can be considered as an alternative to deal with references that is more isolated to the circularity problem during serialization.
Comparison with Newtonsoft.Json
void Test()
{
var node = new Node { Description = "Node 1" };
node.Next = node;
var settings = new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore };
string json = JsonConvert.SerializeObject(node, settings);
Console.WriteLine(json); // Prints: {"Description":"Node 1"}.
}Comparison with existing ReferenceHandler.Preserve setting in S.T.Json
void Test()
{
var node = new Node { Description = "Node 1" };
node.Next = node;
var opts = new JsonSerializerOptions { ReferenceHandler = ReferenceHandler.Preserve };
string json = JsonSerializer.Serialize(node, opts);
Console.WriteLine(json); // Prints: {"$id":"1","Description":"Node 1","Next":{"$ref":"1"}}.
}Risks
One downside is that users are uanble to implement their own ReferenceHandler and cannot make their own "Ignore Cycle" handler. The discrimination between preserve and ignore would occur with an internal flag.
Concerns of adding this feature (users must be aware of these problems when opting-in for it):
- Silent loss of data given that the object where the loop is detected would be ignored from the JSON (see example: Should we add support to ignore cycles on serialization? #40099 (comment)).
- Unable to round-trip data. the JSON may differ depending on the order of serialization (e.g: object properties and dictionary elements enumeration is non-deterministic).