如何反序列化嵌套的 JSON 对象,它是 System.Text.Json 中的字符串?
How do I deserialize a nested JSON object which is a string in System.Text.Json?
我在 ASP.NET 5 MVC 应用程序中反序列化 JSON 使用:
var tulemus = JsonSerializer.Deserialize<EstoJarelMaksTulemnus>(apiResponse, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
public class EstoJarelMaksTulemnus
{
public string[] Errors { get; set; }
public EstoData Data { get; set; }
public string Mac { get; set; }
}
public class EstoData
{
public string Id { get; set; }
public string Status { get; set; }
public string Purchase_url { get; set; }
public string Merchant_reference { get; set; }
public decimal Amount { get; set; }
public string Currency { get; set; }
public bool Is_test { get; set; }
public string Return_url { get; set; }
public string Notification_url { get; set; }
}
这会引发错误:
System.Text.Json.JsonException: The JSON value could not be converted
to Store.Controllers.CheckoutController+EstoData. Path: $.data |
LineNumber: 0 | BytePositionInLine: 497. at
System.Text.Json.ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(Type
propertyType) ...
apiResponse
是单行字符串,包含嵌入的 EstoData
:
{"errors":[],"data":"{\"id\":\"iUW3YiDIz5Ahg5eO8hV7d3Cv7SVbZ913\",\"status\":\"CREATED\",\"purchase_url\":\"https:\\/\\/user.esto.com\\/application\\/iUW3YiDIeO8hV7d3Cv7SVbZ913\",\"merchant_reference\":\"15502\",\"amount\":93.95,\"currency\":\"EUR\",\"is_test\":true,\"return_url\":\"http:\\/\\/localhost:54274\\/CheckoutController\\/EstoJarelmaksOK?tellimus=104742\",\"notification_url\":\"http:\\/\\/localhost:54274\\/CheckoutController\\/EstoJarelmaksTeade?tellimus=104742\"}","mac":"E9C3E61FC347D8043ABDCF464D537C37A609EC878F95B5F526271A2287F2D2E507B5A14FA3AF5F7A6D4CDECB6E8A1DBDF9A5633E0B3AD96DA35FA1C9"}
位置497好像指向Data
属性前mac
.
的结尾
如何将此 JSON 反序列化为 EstoJarelMaksTulemnus
,考虑到 EstoData
在我的对象中是一个具体的嵌套类型,但在JSON?
apiResponse
中的 Data
不是一个对象,它是一个字符串,您可以使用 Newtonsoft Json.Net
将字符串转换为模型,如本期所述:
您需要创建自定义 JsonConverter<T>
,在这种情况下 T
是 EstoData
,以便能够正确反序列化嵌套的 Data
JSON对象.
这应该可以再次对对象进行反序列化和序列化:
StringToEstoDataConverter.cs
public class StringToEstoDataConverter : JsonConverter<EstoData>
{
public override EstoData? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
using (var jsonDoc = JsonDocument.ParseValue(ref reader))
{
var infoData = jsonDoc.RootElement.GetString();
if (infoData != null)
return JsonSerializer.Deserialize<EstoData>(infoData, options);
}
return default;
}
public override void Write(Utf8JsonWriter writer, EstoData value, JsonSerializerOptions options)
{
JsonSerializer.Serialize(writer, value, value.GetType(), options);
}
}
EstoJarelMaksTulemnus.cs
public class EstoJarelMaksTulemnus
{
public string[] Errors { get; set; }
[JsonConverter(typeof(StringToEstoDataConverter))]
public EstoData Data { get; set; }
public string Mac { get; set; }
}
用法:
var tulemus = JsonSerializer.Deserialize<EstoJarelMaksTulemnus>(apiResponse, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
这是一个工作演示:
public class Program
{
public static void Main()
{
var data =
"{\"errors\":[],\"data\":\"{\\"id\\":\\"iUW3YiDIz5Ahg5eO8hV7d3Cv7SVbZ913\\",\\"status\\":\\"CREATED\\",\\"purchase_url\\":\\"https:\\\/\\\/user.esto.ee\\\/application\\\/iUW3YiDIz5Ahg5eO8hV7d3Cv7SVbZ913\\",\\"merchant_reference\\":\\"158502\\",\\"amount\\":93.95,\\"currency\\":\\"EUR\\",\\"is_test\\":true,\\"return_url\\":\\"http:\\\/\\\/localhost:54274\\\/CheckoutController\\\/EstoJarelmaksOK?tellimus=104742\\",\\"notification_url\\":\\"http:\\\/\\\/localhost:54274\\\/CheckoutController\\\/EstoJarelmaksTeade?tellimus=104742\\"}\",\"mac\":\"E9C3E61FC347D80200F542C43ABDCF464D537C37A609EC878F95B5F526271A2287F2D2E507B5A14FA3AF5F7A6D4CDECB6E8A1DBDF9A5633E0B3AD96DA35FA1C9\"}";
var tulemus = JsonSerializer.Deserialize<EstoJarelMaksTulemnus>(data, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
Console.WriteLine(tulemus.Errors.Length);
Console.WriteLine(tulemus.Data.Id);
Console.WriteLine(tulemus.Data.Status);
Console.WriteLine(tulemus.Data.Purchase_url);
Console.WriteLine(tulemus.Data.Merchant_reference);
Console.WriteLine(tulemus.Data.Amount);
Console.WriteLine(tulemus.Data.Currency);
Console.WriteLine(tulemus.Data.Is_test);
Console.WriteLine(tulemus.Data.Return_url);
Console.WriteLine(tulemus.Data.Notification_url);
Console.WriteLine(tulemus.Mac);
}
}
public class StringToEstoDataConverter : JsonConverter<EstoData>
{
public override EstoData? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
using (var jsonDoc = JsonDocument.ParseValue(ref reader))
{
var infoData = jsonDoc.RootElement.GetString();
if (infoData != null)
return JsonSerializer.Deserialize<EstoData>(infoData, options);
}
return default;
}
public override void Write(Utf8JsonWriter writer, EstoData value, JsonSerializerOptions options)
{
JsonSerializer.Serialize(writer, value, value.GetType(), options);
}
}
public class EstoJarelMaksTulemnus
{
public string[] Errors { get; set; }
[JsonConverter(typeof(StringToEstoDataConverter))]
public EstoData Data { get; set; }
public string Mac { get; set; }
}
public class EstoData
{
public string Id { get; set; }
public string Status { get; set; }
public string Purchase_url { get; set; }
public string Merchant_reference { get; set; }
public decimal Amount { get; set; }
public string Currency { get; set; }
public bool Is_test { get; set; }
public string Return_url { get; set; }
public string Notification_url { get; set; }
}
输出:
0
iUW3YiDIz5Ahg5eO8hV7d3Cv7SVbZ913
CREATED
https://user.esto.ee/application/iUW3YiDIz5Ahg5eO8hV7d3Cv7SVbZ913
158502
93.95
EUR
True
http://localhost:54274/CheckoutController/EstoJarelmaksOK?tellimus=104742
http://localhost:54274/CheckoutController/EstoJarelmaksTeade?tellimus=104742
E9C3E61FC347D80200F542C43ABDCF464D537C37A609EC878F95B5F526271A2287F2D2E507B5A14FA3AF5F7A6D4CDECB6E8A1DBDF9A5633E0B3AD96DA35FA1C9
"data" 属性 in your original json 是双重序列化的,所以应该从 json string 到 object
第二次反序列化
所以试试这个代码
var json=...your json;
var jd = JsonSerializer.Deserialize<Root>(json, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
// the second deserialize data property from json string to instance
var jdd= JsonSerializer.Deserialize<Data>(jd.data);
JsonDeserialized result = new JsonDeserialized {errors=jd.errors, data=jdd, mac=jd.mac};
var jsonFixed=JsonSerializer.Serialize(result);
固定json
{
"errors": [],
"data": {
"id": "iUW3YiDIz5Ahg5eO8hV7d3Cv7SVbZ913",
"status": "CREATED",
"purchase_url": "https://user.esto.ee/application/iUW3YiDIz5Ahg5eO8hV7d3Cv7SVbZ913",
"merchant_reference": "158502",
"amount": 93.95,
"currency": "EUR",
"is_test": true,
"return_url": "http://localhost:54274/CheckoutController/EstoJarelmaksOK?tellimus=104742",
"notification_url": "http://localhost:54274/CheckoutController/EstoJarelmaksTeade?tellimus=104742"
},
"mac": "E9C3E61FC347D80200F542C43ABDCF464D537C37A609EC878F95B5F526271A2287F2D2E507B5A14FA3AF5F7A6D4CDECB6E8A1DBDF9A5633E0B3AD96DA35FA1C9"
}
测试
JsonDeserialized deserializedFixedJson = Deserialize<JsonDeserialized>(jsonFixed, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
类
public class JsonDeserialized
{
public List<object> errors { get; set; }
public Data data { get; set; }
public string mac { get; set; }
}
public class Data
{
public string id { get; set; }
public string status { get; set; }
public string purchase_url { get; set; }
public string merchant_reference { get; set; }
public double amount { get; set; }
public string currency { get; set; }
public bool is_test { get; set; }
public string return_url { get; set; }
public string notification_url { get; set; }
}
public class Root
{
public List<object> errors { get; set; }
public string data { get; set; }
public string mac { get; set; }
}
我在 ASP.NET 5 MVC 应用程序中反序列化 JSON 使用:
var tulemus = JsonSerializer.Deserialize<EstoJarelMaksTulemnus>(apiResponse, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
public class EstoJarelMaksTulemnus
{
public string[] Errors { get; set; }
public EstoData Data { get; set; }
public string Mac { get; set; }
}
public class EstoData
{
public string Id { get; set; }
public string Status { get; set; }
public string Purchase_url { get; set; }
public string Merchant_reference { get; set; }
public decimal Amount { get; set; }
public string Currency { get; set; }
public bool Is_test { get; set; }
public string Return_url { get; set; }
public string Notification_url { get; set; }
}
这会引发错误:
System.Text.Json.JsonException: The JSON value could not be converted to Store.Controllers.CheckoutController+EstoData. Path: $.data | LineNumber: 0 | BytePositionInLine: 497. at System.Text.Json.ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(Type propertyType) ...
apiResponse
是单行字符串,包含嵌入的 EstoData
:
{"errors":[],"data":"{\"id\":\"iUW3YiDIz5Ahg5eO8hV7d3Cv7SVbZ913\",\"status\":\"CREATED\",\"purchase_url\":\"https:\\/\\/user.esto.com\\/application\\/iUW3YiDIeO8hV7d3Cv7SVbZ913\",\"merchant_reference\":\"15502\",\"amount\":93.95,\"currency\":\"EUR\",\"is_test\":true,\"return_url\":\"http:\\/\\/localhost:54274\\/CheckoutController\\/EstoJarelmaksOK?tellimus=104742\",\"notification_url\":\"http:\\/\\/localhost:54274\\/CheckoutController\\/EstoJarelmaksTeade?tellimus=104742\"}","mac":"E9C3E61FC347D8043ABDCF464D537C37A609EC878F95B5F526271A2287F2D2E507B5A14FA3AF5F7A6D4CDECB6E8A1DBDF9A5633E0B3AD96DA35FA1C9"}
位置497好像指向Data
属性前mac
.
如何将此 JSON 反序列化为 EstoJarelMaksTulemnus
,考虑到 EstoData
在我的对象中是一个具体的嵌套类型,但在JSON?
apiResponse
中的 Data
不是一个对象,它是一个字符串,您可以使用 Newtonsoft Json.Net
将字符串转换为模型,如本期所述:
您需要创建自定义 JsonConverter<T>
,在这种情况下 T
是 EstoData
,以便能够正确反序列化嵌套的 Data
JSON对象.
这应该可以再次对对象进行反序列化和序列化:
StringToEstoDataConverter.cs
public class StringToEstoDataConverter : JsonConverter<EstoData>
{
public override EstoData? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
using (var jsonDoc = JsonDocument.ParseValue(ref reader))
{
var infoData = jsonDoc.RootElement.GetString();
if (infoData != null)
return JsonSerializer.Deserialize<EstoData>(infoData, options);
}
return default;
}
public override void Write(Utf8JsonWriter writer, EstoData value, JsonSerializerOptions options)
{
JsonSerializer.Serialize(writer, value, value.GetType(), options);
}
}
EstoJarelMaksTulemnus.cs
public class EstoJarelMaksTulemnus
{
public string[] Errors { get; set; }
[JsonConverter(typeof(StringToEstoDataConverter))]
public EstoData Data { get; set; }
public string Mac { get; set; }
}
用法:
var tulemus = JsonSerializer.Deserialize<EstoJarelMaksTulemnus>(apiResponse, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
这是一个工作演示:
public class Program
{
public static void Main()
{
var data =
"{\"errors\":[],\"data\":\"{\\"id\\":\\"iUW3YiDIz5Ahg5eO8hV7d3Cv7SVbZ913\\",\\"status\\":\\"CREATED\\",\\"purchase_url\\":\\"https:\\\/\\\/user.esto.ee\\\/application\\\/iUW3YiDIz5Ahg5eO8hV7d3Cv7SVbZ913\\",\\"merchant_reference\\":\\"158502\\",\\"amount\\":93.95,\\"currency\\":\\"EUR\\",\\"is_test\\":true,\\"return_url\\":\\"http:\\\/\\\/localhost:54274\\\/CheckoutController\\\/EstoJarelmaksOK?tellimus=104742\\",\\"notification_url\\":\\"http:\\\/\\\/localhost:54274\\\/CheckoutController\\\/EstoJarelmaksTeade?tellimus=104742\\"}\",\"mac\":\"E9C3E61FC347D80200F542C43ABDCF464D537C37A609EC878F95B5F526271A2287F2D2E507B5A14FA3AF5F7A6D4CDECB6E8A1DBDF9A5633E0B3AD96DA35FA1C9\"}";
var tulemus = JsonSerializer.Deserialize<EstoJarelMaksTulemnus>(data, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
Console.WriteLine(tulemus.Errors.Length);
Console.WriteLine(tulemus.Data.Id);
Console.WriteLine(tulemus.Data.Status);
Console.WriteLine(tulemus.Data.Purchase_url);
Console.WriteLine(tulemus.Data.Merchant_reference);
Console.WriteLine(tulemus.Data.Amount);
Console.WriteLine(tulemus.Data.Currency);
Console.WriteLine(tulemus.Data.Is_test);
Console.WriteLine(tulemus.Data.Return_url);
Console.WriteLine(tulemus.Data.Notification_url);
Console.WriteLine(tulemus.Mac);
}
}
public class StringToEstoDataConverter : JsonConverter<EstoData>
{
public override EstoData? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
using (var jsonDoc = JsonDocument.ParseValue(ref reader))
{
var infoData = jsonDoc.RootElement.GetString();
if (infoData != null)
return JsonSerializer.Deserialize<EstoData>(infoData, options);
}
return default;
}
public override void Write(Utf8JsonWriter writer, EstoData value, JsonSerializerOptions options)
{
JsonSerializer.Serialize(writer, value, value.GetType(), options);
}
}
public class EstoJarelMaksTulemnus
{
public string[] Errors { get; set; }
[JsonConverter(typeof(StringToEstoDataConverter))]
public EstoData Data { get; set; }
public string Mac { get; set; }
}
public class EstoData
{
public string Id { get; set; }
public string Status { get; set; }
public string Purchase_url { get; set; }
public string Merchant_reference { get; set; }
public decimal Amount { get; set; }
public string Currency { get; set; }
public bool Is_test { get; set; }
public string Return_url { get; set; }
public string Notification_url { get; set; }
}
输出:
0
iUW3YiDIz5Ahg5eO8hV7d3Cv7SVbZ913
CREATED
https://user.esto.ee/application/iUW3YiDIz5Ahg5eO8hV7d3Cv7SVbZ913
158502
93.95
EUR
True
http://localhost:54274/CheckoutController/EstoJarelmaksOK?tellimus=104742
http://localhost:54274/CheckoutController/EstoJarelmaksTeade?tellimus=104742
E9C3E61FC347D80200F542C43ABDCF464D537C37A609EC878F95B5F526271A2287F2D2E507B5A14FA3AF5F7A6D4CDECB6E8A1DBDF9A5633E0B3AD96DA35FA1C9
"data" 属性 in your original json 是双重序列化的,所以应该从 json string 到 object
第二次反序列化所以试试这个代码
var json=...your json;
var jd = JsonSerializer.Deserialize<Root>(json, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
// the second deserialize data property from json string to instance
var jdd= JsonSerializer.Deserialize<Data>(jd.data);
JsonDeserialized result = new JsonDeserialized {errors=jd.errors, data=jdd, mac=jd.mac};
var jsonFixed=JsonSerializer.Serialize(result);
固定json
{
"errors": [],
"data": {
"id": "iUW3YiDIz5Ahg5eO8hV7d3Cv7SVbZ913",
"status": "CREATED",
"purchase_url": "https://user.esto.ee/application/iUW3YiDIz5Ahg5eO8hV7d3Cv7SVbZ913",
"merchant_reference": "158502",
"amount": 93.95,
"currency": "EUR",
"is_test": true,
"return_url": "http://localhost:54274/CheckoutController/EstoJarelmaksOK?tellimus=104742",
"notification_url": "http://localhost:54274/CheckoutController/EstoJarelmaksTeade?tellimus=104742"
},
"mac": "E9C3E61FC347D80200F542C43ABDCF464D537C37A609EC878F95B5F526271A2287F2D2E507B5A14FA3AF5F7A6D4CDECB6E8A1DBDF9A5633E0B3AD96DA35FA1C9"
}
测试
JsonDeserialized deserializedFixedJson = Deserialize<JsonDeserialized>(jsonFixed, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
类
public class JsonDeserialized
{
public List<object> errors { get; set; }
public Data data { get; set; }
public string mac { get; set; }
}
public class Data
{
public string id { get; set; }
public string status { get; set; }
public string purchase_url { get; set; }
public string merchant_reference { get; set; }
public double amount { get; set; }
public string currency { get; set; }
public bool is_test { get; set; }
public string return_url { get; set; }
public string notification_url { get; set; }
}
public class Root
{
public List<object> errors { get; set; }
public string data { get; set; }
public string mac { get; set; }
}