使用 System.Text.Json.Serialization.JsonConverter 解析 JSON 序列化过程中复杂类型的循环引用

2024-05-25

有一个复杂类型引用相同类型的对象(有时是同一对象):

public class User
{
    public string Name { get; set; }

    public int Age { get; set; }

    public User Reference { get; set; }
}

有一个自定义 JsonConverter (System.Text.Json.Serialization) 实现来反序列化此对象,避免一些特殊属性。

public class UserJsonConverter : JsonConverter<User>
{
    public override User Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        throw new NotImplementedException();
    }

    public override void Write(Utf8JsonWriter writer, User value, JsonSerializerOptions options)
    {
        writer.WriteStartObject();

        // write the name property only and ignore the age
        writer.WriteString(nameof(value.Name), value.Name);

        writer.WritePropertyName(nameof(value.Reference));
        JsonSerializer.Serialize(writer, value.Reference, options);

        writer.WriteEndObject();
    }
}

但尚不清楚在对象指向自身的情况下如何配置引用解析。例子:

var user = new User
{
    Age = 10,
    Name = "username"
};

user.Reference = user;

var options = new JsonSerializerOptions();
options.ReferenceHandler = ReferenceHandler.Preserve;
options.Converters.Add(new UserJsonConverter());

var result = JsonSerializer.Serialize(user, user.GetType(), options);

异常发生:

System.Text.Json.JsonException. A possible object cycle was detected. This can either be due to a cycle or if the object depth is larger than the maximum allowed depth of 64. Consider using ReferenceHandler.Preserve on JsonSerializerOptions to support cycles

我们使用System.Text.Json,版本=5.0.0.0

默认对象转换器的所有基于“$ref”和“$id”的方法都是内部的,不可使用。我看到的唯一方法是在序列化之前简化某些 DTO 中的 User 对象,并在没有此自定义转换器的情况下使用它。

但也许有人知道是否有正确的方法来解析自定义 JsonConverter 中的这些引用?


基于自定义引用处理程序使用的解决方案

UserJsonConverter 更改:

public override void Write(Utf8JsonWriter writer, User value, JsonSerializerOptions options)
{
    // use reference handler manually
    var v_resolver = options.ReferenceHandler?.CreateResolver();
    if (v_resolver != null)
    {
        var v_refID = v_resolver.GetReference(value, out bool alreadyExists);
        if (alreadyExists)
        {
            writer.WriteStartObject();
            writer.WriteString(JsonEncodedText.Encode("$ref", encoder: null), v_refID);
            writer.WriteEndObject();
            return;
        }
        else
        {
            writer.WriteStartObject();
            writer.WriteString(JsonEncodedText.Encode("$id", encoder: null), v_refID);
        }
    }

    //writer.WriteStartObject();

    ...
}

用法变化:

...
var options = new JsonSerializerOptions();
options.ReferenceHandler = new CutomReferenceHandler();
...

自定义参考处理程序实现可在此处获得:https://github.com/dotnet/docs/issues/21777#issuecomment-736751404 https://github.com/dotnet/docs/issues/21777#issuecomment-736751404 or docs https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-preserve-references?pivots=dotnet-5-0#persist-reference-metadata-across-multiple-serialization-and-deserialization-calls

它有效,但我有点害怕以这种方式使用它,因为内部引用解析器逻辑将来可能会改变($id,$refs)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 System.Text.Json.Serialization.JsonConverter 解析 JSON 序列化过程中复杂类型的循环引用 的相关文章

  • 在 .Net 托管的 IronPython 脚本中设置和获取变量

    我正在尝试使用 Net 控制台应用程序中托管的 IronPython 来构建验证规则引擎的原型 我已经将脚本精简到我认为的基础内容 var engine Python CreateEngine engine Execute from Sys
  • 在 HBase 中存储和检索字符串数组

    我读过这个答案 如何将复杂对象存储到hadoop Hbase中 https stackoverflow com questions 4086684 how to store complex objects into hadoop hbase
  • 调整图像的亮度、对比度和伽玛值

    在 NET 中调整图像的亮度 对比度和伽玛值的简单方法是什么 c and gdi have a simple way to control the colors that are drawn It s basically a ColorMa
  • C# - 方法必须有返回类型

    我在调用 C 中的方法时遇到问题 不断收到消息 方法 计算 必须有返回类型 using System Diagnostics namespace WindowsFormsApplication1 public partial class F
  • “你好世界!!”在 .NET 4 中生成 3500 个页面错误

    我正在运行 Windows Vista 和 Visual Studio 2010 使用 NET 4 2 GB RAM 和大约 800 MB 可用空间 我创建了一个 Windows 窗体应用程序 但没有向其中添加任何代码 只需在发布模式下编译
  • 在一个数据访问层中处理多个连接字符串

    我有一个有趣的困境 我目前有一个数据访问层 它必须与多个域一起使用 并且每个域都有多个数据库存储库 具体取决于所调用的存储过程 目前 我只需使用 SWITCH 语句来确定应用程序正在运行的计算机 并从 Web config 返回适当的连接字
  • 匿名类上的 NotSerializedException

    我有一个用于过滤项目的界面 public interface KeyValFilter extends Serializable public static final long serialVersionUID 7069537470113
  • 用于 FTP 的文件系统观察器

    我怎样才能实现FileSystemWatcherFTP 位置 在 C 中 这个想法是 每当 FTP 位置添加任何内容时 我都希望将其复制到我的本地计算机 任何想法都会有所帮助 这是我之前问题的后续使用 NET 进行选择性 FTP 下载 ht
  • VB.NET 中的静态方法实现

    我很困惑Static在 VB NET 中的实现 在 C 中 我们可以创建静态类和静态方法来为我们的应用程序编写实用方法 现在 VB NET 让我们创建Module代替静态类 如果我们在模块中创建一个方法 默认情况下它会变成静态的 但在我的应
  • SQLite .NET 性能,如何加快速度?

    在我的系统上 约 86000 个 SQLite 插入需要长达 20 分钟 意味着每秒约 70 个插入 我要做数百万 我怎样才能加快速度 对每一行的 SQLiteConnection 对象调用 Open 和 Close 会降低性能吗 交易有帮
  • WPF:Prism 对于小型应用程序来说是不是太过分了?

    如果我不将我的应用程序分成不同的模块 否则我会认为 Prism 确实是可行的方法 我应该使用 Prism 吗 我知道 Prism 提供了一个方便的实现ICommand 我可以自己在一页代码中完成 并为我们提供IEventAggregator
  • 为什么两个不同的 Base64 字符串的转换会返回相等的字节数组?

    我想知道为什么从 base64 字符串转换会为不同的字符串返回相同的字节数组 const string s1 dg const string s2 dq byte a1 Convert FromBase64String s1 byte a2
  • 按成员序列化

    我已经实现了template
  • .NET 中是否有内置函数可以对密码进行哈希处理?

    我看到这个问题加密 散列数据库中的纯文本密码 https stackoverflow com questions 287517 encrypting hashing plain text passwords in database 我知道我
  • C#中如何移动PictureBox?

    我已经使用此代码来移动图片框pictureBox MouseMove event pictureBox Location new System Drawing Point e Location 但是当我尝试执行时 图片框闪烁并且无法识别确切
  • 控件的命名约定[重复]

    这个问题在这里已经有答案了 Microsoft 在其网站上提供了命名指南 here http msdn microsoft com en us library xzf533w0 VS 71 aspx 我还有 框架设计指南 一书 我找不到有关
  • 如何序列化/反序列化自定义数据集

    我有一个 winforms 应用程序 它使用强类型的自定义数据集来保存数据进行处理 它由数据库中的数据填充 我有一个用户控件 它接受任何自定义数据集并在数据网格中显示内容 这用于测试和调试 为了使控件可重用 我将自定义数据集视为普通的 Sy
  • C# - OutOfMemoryException 在 JSON 文件上保存列表

    我正在尝试保存压力图的流数据 基本上我有一个压力矩阵定义为 double pressureMatrix new double e Data GetLength 0 e Data GetLength 1 基本上 我得到了其中之一pressur
  • 如何防止用户控件表单在 C# 中处理键盘输入(箭头键)

    我的用户控件包含其他可以选择的控件 我想实现使用箭头键导航子控件的方法 问题是家长控制拦截箭头键并使用它来滚动其视图什么是我想避免的事情 我想自己解决控制内容的导航问题 我如何控制由箭头键引起的标准行为 提前致谢 MTH 这通常是通过重写
  • 使用.NET技术录制屏幕视频[关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 有没有一种方法可以使用 NET 技术来录制屏幕 无论是桌面还是窗口 我的目标是免费的 我喜欢小型 低

随机推荐