ASP.NET Core 6:处理非常规非数组JSON并转换为可用对象
问题解答
1. 遍历JSON结构
由于你使用GetFromJsonAsync<dynamic>获取的JSON在System.Text.Json中实际是JsonElement类型,可通过EnumerateObject()方法逐层遍历所有属性:
var client = new HttpClient(); // 直接获取JsonElement,比dynamic更便于结构化遍历 var jsonElement = await client.GetFromJsonAsync<JsonElement>(url); // 遍历顶级的ID属性(如"1"、"2") foreach (var idProperty in jsonElement.EnumerateObject()) { // 将字符串ID转为int类型 int id = int.Parse(idProperty.Name); // 获取当前ID对应的日期集合对象 var dateContainer = idProperty.Value; // 遍历每个日期属性(如"2023-03-10") foreach (var dateProperty in dateContainer.EnumerateObject()) { DateTime date = DateTime.Parse(dateProperty.Name); // 获取当前日期对应的Baa数组 var baaElements = dateProperty.Value; // 遍历每个Baa对象 foreach (var baaElement in baaElements.EnumerateArray()) { string label = baaElement.GetProperty("label").GetString(); int prop1 = baaElement.GetProperty("prop1").GetInt32(); int prop2 = baaElement.GetProperty("prop2").GetInt32(); // 此处可对每个Baa对象做业务处理 } } }
2. 转换为强类型对象
原JSON本质是字符串ID为键、日期字典为值的顶级字典,日期字典又是字符串日期为键、Baa列表为值的二级字典。你可以选择两种方式转换为自定义强类型:
方式一:手动转换(简单直接)
先反序列化为字典结构,再手动映射到你的MyObject、Foo、Baa类:
// 定义强类型类 class MyObject { public int Id { get; set; } public List<Foo> Foos { get; set; } = new List<Foo>(); } class Foo { public DateTime Date { get; set; } public List<Baa> Baas { get; set; } = new List<Baa>(); } class Baa { public string Label { get; set; } public int Prop1 { get; set; } public int Prop2 { get; set; } } // 转换代码 var client = new HttpClient(); // 先反序列化为字典结构 var rawDict = await client.GetFromJsonAsync<Dictionary<string, Dictionary<string, List<Baa>>>>(url); // 手动映射到强类型列表 var myObjects = rawDict.Select(kv => new MyObject { Id = int.Parse(kv.Key), Foos = kv.Value.Select(dateKv => new Foo { Date = DateTime.Parse(dateKv.Key), Baas = dateKv.Value }).ToList() }).ToList();
方式二:自定义JSON转换器(自动转换)
如果需要频繁转换,可编写自定义JsonConverter实现自动解析:
// 强类型类定义同上 class MyObject { /* ... */ } class Foo { /* ... */ } class Baa { /* ... */ } // 自定义转换器 public class MyObjectListConverter : JsonConverter<List<MyObject>> { public override List<MyObject> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { var result = new List<MyObject>(); if (reader.TokenType != JsonTokenType.StartObject) throw new JsonException("JSON格式错误,预期为对象"); while (reader.Read()) { if (reader.TokenType == JsonTokenType.EndObject) break; // 读取ID键 string idStr = reader.GetString(); if (!int.TryParse(idStr, out int id)) throw new JsonException($"ID {idStr} 格式无效"); reader.Read(); // 移动到ID对应的值 var myObj = new MyObject { Id = id }; // 读取日期对象 if (reader.TokenType != JsonTokenType.StartObject) throw new JsonException("日期集合格式错误"); while (reader.Read()) { if (reader.TokenType == JsonTokenType.EndObject) break; // 读取日期字符串 string dateStr = reader.GetString(); if (!DateTime.TryParse(dateStr, out DateTime date)) throw new JsonException($"日期 {dateStr} 格式无效"); reader.Read(); // 移动到日期对应的Baa数组 // 反序列化Baa列表 var baas = JsonSerializer.Deserialize<List<Baa>>(ref reader, options); myObj.Foos.Add(new Foo { Date = date, Baas = baas }); } result.Add(myObj); } return result; } // 如果不需要序列化回JSON,可忽略Write方法 public override void Write(Utf8JsonWriter writer, List<MyObject> value, JsonSerializerOptions options) { throw new NotImplementedException(); } } // 使用转换器 var options = new JsonSerializerOptions(); options.Converters.Add(new MyObjectListConverter()); var client = new HttpClient(); var myObjects = await client.GetFromJsonAsync<List<MyObject>>(url, options);
内容的提问来源于stack exchange,提问作者Henrik Ravn
相关产品推荐
相关产品推荐

