В моем приложении C# я анализирую API третьей части этого API. У меня нет какой-либо схемы или спецификаций: для анализа ответов я обычно собираю несколько ответов и пишу классы, соответствующие JSON (это может быть это легко сделать с помощью Visual Studio или онлайн с помощью JSON2CSHARP).
Но в этом подходе есть проблема: когда значения для ключа равны нулю, я не могу идти дальше в десумировании классов подгонки значений. В этих случаях я хотел бы использовать строку? в качестве типа свойства и поместить в значение свойства сериализованный вложенный JObject или JArray.
Поэтому, когда приложение выдало исключение при чтении следующее вложенное свойство:
.registrations[0].product_info
Newtonsoft.Json.JsonReaderException: Unexpected character encountered while parsing value: {. Path '
.registrations[0].product_info', line 1, position 5138
потому что вместо «product_info»: null,
я получил
{
"head_test":"------HEAD-------",
"product_info": {
"product_data": [
{
"product_xtra": {
"product_xtra_id": "",
"product_xtra_type": "",
"unit_price": "",
"vat_rate": 0.22
},
"amount": 2,
"price": ""
}
],
"product_total_price": ""
},
"tail_test":"------TAIL-------",
}
Поэтому я написал конвертер следующим образом:
public class JsonObjectToStringConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
if (typeof(TValue).IsAssignableFrom(objectType))
{
return true;
}
else if(base.CanWrite)
{
return true;
}
return false;
}
public override bool CanRead => base.CanRead;
public override bool CanWrite => base.CanWrite;
public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
{
var token = serializer.Deserialize(reader);
try
{
return token?.ToObject(objectType);
}
catch(Exception ex)
{
Log.Error(ex, "Failed to convert {token} to {objectType}", token, objectType);
return token?.ToString();
}
}
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
{
if(value == null)
{
writer.WriteNull();
return;
}
try
{
var token = Newtonsoft.Json.Linq.JToken.FromObject(value);
token.WriteTo(writer);
}
catch (Exception ex)
{
Log.Error(ex, "Failed to convert {value} to json", value);
writer.WriteValue(value.ToString());
}
}
}
Мой вопрос: могу ли я избежать блока try/catch, чтобы проверить, можно ли нормально десериализовать объект? Как я могу это сделать?
Вчера я проверил это, добавив атрибут в целевой класс DTO.
class Root{
[JsonProperty("head_test")]
public string? Head { get; set; }
[JsonProperty("product_info")]
[JsonConverter(typeof(JsonObjectToStringConverter))]
public string? ProductInfo { get; set; }
[JsonProperty("tail_test")]
public string? Tail { get; set; }
}
Кажется, это работает, но я хотел бы улучшить это. Спасибо.
Я добавил сюда скрипт с рабочим фрагментом.
using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
public class Program
{
static string json = """
{
"head_test":"------HEAD-------",
"product_info": {
"product_data": [
{
"product_xtra": {
"product_xtra_id": "",
"product_xtra_type": "",
"unit_price": "",
"vat_rate": 0.22
},
"amount": 2,
"price": ""
}
],
"product_total_price": ""
},
"tail_test":"------TAIL-------",
}
""";
static string json2 = """
{
"head_test":"------HEAD-------",
"product_info": "----INFO-----",
"tail_test":"------TAIL-------",
}
""";
static string json3 = """
{
"head_test":"------HEAD-------",
"product_info": null,
"tail_test":"------TAIL-------",
}
""";
public static void Main()
{
Console.WriteLine(json);
var root = JsonConvert.DeserializeObject(json);
Console.WriteLine(root.ProductInfo ?? "");
Console.WriteLine(json2);
var root2 = JsonConvert.DeserializeObject(json2);
Console.WriteLine(root2.ProductInfo ?? "");
Console.WriteLine(json3);
var root3 = JsonConvert.DeserializeObject(json3);
Console.WriteLine(root3.ProductInfo ?? "");
}
}
class Root{
[JsonProperty("head_test")]
public string? Head { get; set; }
[JsonProperty("product_info")]
[JsonConverter(typeof(JsonObjectToStringConverter))]
public string? ProductInfo { get; set; }
[JsonProperty("tail_test")]
public string? Tail { get; set; }
}
class JsonObjectToStringConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
if (typeof(TValue).IsAssignableFrom(objectType))
{
return true;
}
else if(base.CanWrite)
{
return true;
}
return false;
}
public override bool CanRead => base.CanRead;
public override bool CanWrite => base.CanWrite;
public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
{
var token = serializer.Deserialize(reader);
try
{
return token?.ToObject(objectType);
}
catch(Exception ex)
{
return token?.ToString();
}
}
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
{
if(value == null)
{
writer.WriteNull();
return;
}
try
{
var token = Newtonsoft.Json.Linq.JToken.FromObject(value);
token.WriteTo(writer);
}
catch (Exception ex)
{
writer.WriteValue(value.ToString());
}
}
}
Подробнее здесь: https://stackoverflow.com/questions/792 ... own-fields
Десериализация неизвестных полей NewtonSoft JSON ⇐ C#
-
- Похожие темы
- Ответы
- Просмотры
- Последнее сообщение
-
-
Newtonsoft.Json.Schema неправильно проверяет полезную нагрузку JSON по схеме JSON.
Anonymous » » в форуме C# - 0 Ответы
- 67 Просмотры
-
Последнее сообщение Anonymous
-
-
-
Newtonsoft.Json.Schema неправильно проверяет полезную нагрузку JSON по схеме JSON.
Anonymous » » в форуме C# - 0 Ответы
- 43 Просмотры
-
Последнее сообщение Anonymous
-