Десериализация неизвестных полей NewtonSoft JSONC#

Место общения программистов 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());
}

}
}


Подробнее здесь: 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 Ответы
    6 Просмотры
    Последнее сообщение 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#»