c# - 如何在 angular2+ 中序列化/反序列化 .NET 类型的 JSON
问题描述
我正在从Angular 客户端调用.NET Web Api ,并使用JSON来序列化/反序列化数据。
我正在尝试反序列化包含Detector列表的Model对象。Detector 是一个抽象类,有两个继承的子类:TextDetector和ColorDetector。
为了能够识别在反序列化过程中需要实例化哪种类型的 Detector,我将TypeNameHandling.Auto设置为我的 JsonSerializerSettings(.NET 端)。
包含 TextDetector 的模型的典型获取响应
{
"Detectors": {
"$type": "System.Collections.Generic.HashSet`1[[I2D_Api.Models.Detector, I2D Api]], System.Core",
"$values": [
{
"$type": "I2D_Api.Models.TextDetector, I2D Api",
"Id": 1,
"Name": "Detector0",
"Bounds": "0, 0, 0, 0"
}
]
},
"Id": 1,
"Name": "Modèle 0",
"ImgModelLink": "https://gamewave.fr/static/images/medias/upload/Fortnite/canards/Fortnite_20180515121231.jpg"
}
但我不喜欢这个解决方案(我什至无法工作),因为这表明我必须在每个客户端请求(Post 或 Put)上手动键入我的数据才能正确反序列化 .NET 端......除此之外,由于$ 前缀,我还没有成功将此 JSON 反序列化为模型对象客户端(但我猜这是可行的)
我想我走错路了,我已经搜索但找不到另一种方法来传递这个集合,这似乎是一种肮脏的方式。还有另一种方法吗?
注意:我使用的是 EntityFramework,这是我的 get 方法
[ResponseType(typeof(Model))]
public IHttpActionResult GetModel(int id)
{
Model model = db.Models.Find(id);
if (model == null)
{
return NotFound();
}
return Ok(model);
}
编辑:所以我关注了@dbc链接:反序列化没有类型信息的多态json类,这正是我想要的。我实现了一个 Json 转换器,它知道子类基于缺少的属性Color实例化(没有颜色属性 = TextDetector,颜色属性 = ColorDetector)。
还用 Detector 类中的 X、Y、Width 和 Height 属性替换了我的 Bounds 属性(JsonProperty.ValueProvider无法提取结构上的值)(不是问题)。最后将TypeNameHandling更改为Object。
但是现在我得到了一个我不明白的 stackoverflow 异常。请注意,TextDetector 没有比Detector Errors 更多的属性/属性来自我的DetectorConverter中的这一行
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JObject item = JObject.Load(reader); // This throw stackoverflow exception
if (item["Color"] == null)
{
return item.ToObject<TextDetector>();
}
else
{
return item.ToObject<ColorDetector>();
}
}
在第一次ReadJson执行时,也不例外。但是,它看起来像JObject.load(reader)在内部导致了一个循环,我在堆栈中看不到它,因为它是外部代码。我唯一知道的是,从阅读器加载后的项目类型是Detector在第一次执行时然后是TextDetector,永远循环..
解决方案
感谢@dbc 为我指明了正确的方向。
此链接的接受答案是正确答案。
我想添加一些精度:
- 使用这个解决方案,我不得不删除我的抽象类的结构属性,因为转换无法读取它们(我认为这是可能的,但我更喜欢将结构的属性提取到我的抽象类)
- 在读取传入的 Json 时,您可能会遇到stackoverflow 异常。您可以通过使用
serializer.populate
替换 JObjecttoItem
方法来解决此问题。或者,这就是我所做的,将 JSON NoConverter 应用于具体的子类
NoConverter 类,您可以像其他所有 JsonConverter 一样复制/粘贴并将其用作属性
public class NoConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return false;
}
public override bool CanRead { get { return false; } }
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override bool CanWrite { get { return false; } }
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
推荐阅读
- android - 显示对话框后更改警告对话框的正按钮文本
- android - 画布 drawText 和表情符号 alpha 颜色
- python - Selenium 不会在远程服务器上无头启动
- r - 通过引用将 R data.table 的列作为矩阵访问
- json - 如何使用 Java 代码读取 CSV 并解析 JSON
- c# - .net 核心依赖注入
- ios - 无法在 iOS 模拟器中运行 ionic 项目。在xcode中获得权限被拒绝
- c++ - C++14:如何将模板函数与 `iterator` 和 `const_iterator` 一起使用
- javascript - 使用 javascript 更改图像 src 的问题
- javascript - WebRTC客户端无法在视频元素上显示远程流