繁体   English   中英

使用 System.Text.Json 加载具有对 Blazor Wasm 的循环引用的对象

[英]Load objects with circular references to Blazor Wasm with System.Text.Json

问题

我正在使用 Blazor WASM,它与使用 ASP.NET 内核构建的 RESTful API 进行通信。 我需要加载带有循环引用的对象。

使用默认序列化设置,这会产生 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 32. Consider using ReferenceHandler.Preserve on JsonSerializerOptions 
to support cycles.

我的尝试

我在服务器上的 Startup.cs 中向 ConfigureServices() 添加了以下几行:

services.AddControllersWithViews().AddJsonOptions(options => {
   options.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.Preserve;
});

并修改了客户端上的请求:

data = await Http.GetFromJsonAsync<My.Shared.DataObject[]>(
    "api/GetDataObjects", 
    new System.Text.Json.JsonSerializerOptions() { 
        ReferenceHandler = System.Text.Json.Serialization.ReferenceHandler.Preserve
    }
);

当我运行它时,服务器会返回合理的响应: 回复

但是客户端在解析响应时抛出 System.Text.Json.JsonException :

Cannot parse a JSON object containing metadata properties like '$id' into an array or immutable 
collection type. Type 'My.Shared.DataObject[]'. 

Path: $.$id | LineNumber: 0 | BytePositionInLine: 7

为什么会这样? 如何解决?

错误消息是不言自明的:

无法将包含“$id”等元数据属性的 JSON object 解析为数组或不可变集合类型。 键入“My.Shared.DataObject[]”

文档证实了这一点:

对于值类型、不可变类型和 arrays,没有引用元数据被序列化。 在反序列化时,如果找到$ref$id则会引发异常。

您需要反序列化为List<DataObject> ,而不是数组:

data = await Http.GetFromJsonAsync<List<My.Shared.DataObject>>(
    "api/GetDataObjects", 
    new System.Text.Json.JsonSerializerOptions() { 
        ReferenceHandler = System.Text.Json.Serialization.ReferenceHandler.Preserve
    }
);

笔记:

  • 该限制可能已实现,因为 arrays 和只读 collections 只能在读入它们的项目后才能完全构造 - 但ReferenceHandler缩进以支持从子级到父级的反向引用以及从 ZA8CFFDE6331BD59B62ACZ 到自身的递归自引用。 并且不清楚如何为只读 collections 或只能在其子项构建后才能构建的不可变对象实现此类功能。

    Json.NET 具有类似的限制,请参阅无法保留对数组或只读列表或从非默认构造函数创建的列表的引用以获取详细信息。

  • 如果您不需要 collections 的参考保存,您可以将您的集合序列化为数组,并且数组本身不会包含$id信息。 (其项目仍将包含所需的$id属性。)

    即在您的服务器端,您必须通过网络发送List<My.Shared.DataObject> 相反,如果您发送My.Shared.DataObject []根容器将是一个简单的 JSON 数组,而不是 JSON object 与参考信息和嵌套$values数组。

    为了进行比较,而 Json.NET 通过设置PreserveReferencesHandling.Objects , System.Text.Json 似乎无法通过选项提供此级别的控制,仅支持为对象保留引用,而不支持 collections。

  • 之后,您始终可以使用ToArray()List<DataObject>转换为数组。

演示小提琴在这里

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM