Десериализация NewtonSoft JSON неизвестных полей [дубликат]C#

Место общения программистов C#
Ответить Пред. темаСлед. тема
Anonymous
 Десериализация NewtonSoft JSON неизвестных полей [дубликат]

Сообщение Anonymous »

В моем приложении 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());
}

}
}
[EDIT] Мое программное обеспечение выдало другое исключение, вот зарегистрированная трассировка

Код: Выделить всё

2024-11-25 22:16 +01:00: [22:16:14 ERR] Failed to convert [[[[[[[[]], [[]], [[]], [[]]]], [[]], [[]]]]], [[]]] to System.String
2024-11-25 22:16 +01:00: System.ArgumentException: Can not convert Object to String.
2024-11-25 22:16 +01:00:    at Newtonsoft.Json.Linq.JToken.op_Explicit(JToken value)
2024-11-25 22:16 +01:00:    at Newtonsoft.Json.Linq.JToken.ToObject(Type objectType)
2024-11-25 22:16 +01:00:    at [....].JsonConverters.JsonObjectToStringConverter`1.ReadJson(JsonReader reader, Type objectType, Object existingValue, JsonSerializer serializer) in [...]\JsonConverters\JsonObjectToStringConverter.cs:line 37
2024-11-25 22:16 +01:00: [22:16:14 ERR] Failed to convert [[[[[[[[]], [[]], [[]], [[]]]], [[]], [[]]]]], [[]]] to System.String
2024-11-25 22:16 +01:00: System.ArgumentException: Can not convert Object to String.
2024-11-25 22:16 +01:00:    at Newtonsoft.Json.Linq.JToken.op_Explicit(JToken value)
2024-11-25 22:16 +01:00:    at Newtonsoft.Json.Linq.JToken.ToObject(Type objectType)
2024-11-25 22:16 +01:00:    at [...].JsonConverters.JsonObjectToStringConverter`1.ReadJson(JsonReader reader, Type objectType, Object existingValue, JsonSerializer serializer) in [...]\JsonConverters\JsonObjectToStringConverter.cs:line 37
[Edit]
Я прочитал вопрос «Десериализовать json с известными и неизвестными полями», в котором задается вопрос о json с неизвестными свойствами типа «_unknown_field_name_1»: «некоторое значение» , а мой json больше похож на

Код: Выделить всё

{
"id": "",
"name": "",
"product_info": null,
[...Other fields...]
}
Моя цель — управлять всеми неизвестными значениями свойств (где появляется значение null), сохраняя их в виде строк с фрагментом json в них.
Если я использую

Код: Выделить всё

// extra fields
[JsonExtensionData]
private IDictionary _extraStuff;
Я мог бы получить JToken, но мне придется использовать промежуточный объект для хранения дополнительных данных и их обработки, поэтому мне придется написать собственный код.

Подробнее здесь: https://stackoverflow.com/questions/792 ... own-fields
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение
  • Десериализация NewtonSoft JSON неизвестных полей [дубликат]
    Anonymous » » в форуме C#
    0 Ответы
    18 Просмотры
    Последнее сообщение Anonymous
  • Десериализация неизвестных полей NewtonSoft JSON
    Anonymous » » в форуме C#
    0 Ответы
    22 Просмотры
    Последнее сообщение Anonymous
  • Десериализация C# Newtonsoft JSON: значение пустого списка, представленное как «{}» вместо «[]», вызывает исключение
    Anonymous » » в форуме C#
    0 Ответы
    24 Просмотры
    Последнее сообщение Anonymous
  • Newtonsoft.Json.Schema неправильно проверяет полезную нагрузку JSON по схеме JSON.
    Anonymous » » в форуме C#
    0 Ответы
    67 Просмотры
    Последнее сообщение Anonymous
  • Newtonsoft.Json.Schema неправильно проверяет полезную нагрузку JSON по схеме JSON.
    Anonymous » » в форуме C#
    0 Ответы
    43 Просмотры
    Последнее сообщение Anonymous

Вернуться в «C#»