#c# #json #asp.net-web-api #json.net #deserialization
#c# #.net #json #сериализация #json.net
Вопрос:
Я пытаюсь десериализовать некоторые объекты JSON с помощью Json.NET . Однако я обнаружил, что при десериализации объекта, у которого нет свойств, которые я ищу, ошибка не выдается, но при обращении к свойствам возвращается значение по умолчанию для них. Важно, чтобы я мог определить, когда я десериализовал объект неправильного типа. Пример кода:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace Json_Fail_Test
{
class Program
{
[JsonObject(MemberSerialization.OptOut)]
private class MyJsonObjView
{
[JsonProperty("MyJsonInt")]
public int MyJsonInt { get; set; }
}
const string correctData = @"
{
'MyJsonInt': 42
}";
const string wrongData = @"
{
'SomeOtherProperty': 'fbe8c20b'
}";
static void Main(string[] args)
{
var goodObj = JsonConvert.DeserializeObject<MyJsonObjView>(correctData);
System.Console.Out.WriteLine(goodObj.MyJsonInt.ToString());
var badObj = JsonConvert.DeserializeObject<MyJsonObjView>(wrongData);
System.Console.Out.WriteLine(badObj.MyJsonInt.ToString());
}
}
}
Вывод этой программы:
42
0
Я бы предпочел, чтобы было выдано исключение для автоматического сбоя. Кроме этого, есть ли способ определить, не удалось ли сериализации найти параметр?
Я знаю, что могу проанализировать данные с помощью объекта Json, а затем проверить наличие параметра с помощью поиска значения ключа, но кодовая база, в которой я нахожусь, использует приведенный выше шаблон, и я хотел бы сохранить это согласованным, если это возможно.
Ответ №1:
Json.Сетевой сериализатор имеет MissingMemberHandling
настройку, которую вы можете установить на Error
. (Значение по умолчанию равно Ignore
.) Это заставит сериализатор выдавать JsonSerializationException
во время десериализации всякий раз, когда он встречает свойство JSON, для которого нет соответствующего свойства в целевом классе.
static void Main(string[] args)
{
try
{
JsonSerializerSettings settings = new JsonSerializerSettings();
settings.MissingMemberHandling = MissingMemberHandling.Error;
var goodObj = JsonConvert.DeserializeObject<MyJsonObjView>(correctData, settings);
System.Console.Out.WriteLine(goodObj.MyJsonInt.ToString());
var badObj = JsonConvert.DeserializeObject<MyJsonObjView>(wrongData, settings);
System.Console.Out.WriteLine(badObj.MyJsonInt.ToString());
}
catch (Exception ex)
{
Console.WriteLine(ex.GetType().Name ": " ex.Message);
}
}
Результат:
42
JsonSerializationException: Could not find member 'SomeOtherProperty' on object
of type 'MyJsonObjView'. Path 'SomeOtherProperty', line 3, position 33.
Смотрите: параметр MissingMemberHandling.
Комментарии:
1. Я действительно нашел класс settings, копаясь в документации, но, должно быть, я просмотрел это свойство. Я в некотором роде дерьмовый читатель. Большое спасибо; это идеально.
2. @BrianRogers Спасибо. Это мне очень помогло. Есть ли у вас какая-либо ссылка для дальнейшего изучения синтаксического анализа JSON, особенно проблем с отсутствием и обработкой нулевых значений?
3. У меня довольно похожая проблема. Если в JSON отсутствует один член целевого класса, десериализатор проигнорирует это и установит для него значение null. Даже если для параметра MissingMember установлено значение error.
4. Уже найдено решение. Использовал атрибуты, чтобы пометить моих участников по мере необходимости.
5. Примером может быть: десериализация пустой строки json «{}» в любой тип. Это установит все значения в этом типе равными null. Но я хочу исключение, если тип не соответствует json.
Ответ №2:
Просто добавьте [JsonProperty(Required = Required.Always)]
к требуемым свойствам, и это вызовет исключение, если свойство отсутствует во время десериализации.
[JsonProperty(Required = Required.Always)]
public int MyJsonInt { get; set; }
Комментарии:
1. Это решает дополнительную проблему. Если ваша модель обладает свойством, которого нет в вашем JSON , и вы хотите, чтобы это было ошибкой, используйте
[JsonProperty(Required = Required.Always)]
. Смотрите: Требуется атрибут JsonProperty . Если ваш JSON обладает свойством, которого нет в вашей модели , и вы хотите, чтобы это было ошибкой, используйтеMissingMemberHandling = MissingMemberHandling.Error
.
Ответ №3:
Добавьте следующий атрибут в обязательные свойства:
[DataMember(IsRequired = true)]
Если элемент отсутствует, он выдаст файл Newtonsoft.Json.Исключение JsonSerializationException.
Как Брайан предложил ниже, вам также понадобится этот атрибут в вашем классе:
[DataContract]
Комментарии:
1. Вы уверены в этом? Я попытался добавить атрибут, и никаких исключений не выдано. И программа по-прежнему выводит 0.
2. Это решение будет работать только в том случае, если у вас есть
[DataContract]
в вашем классе И у вас нет[JsonProperty]
в члене. (JsonProperty
переопределяетDataMember
.) Однако вы могли бы установить дляRequired
параметра в[JsonProperty]
атрибуте значениеRequired.Always
, чтобы выполнить то же самое.3. свойства @DubiousPusher должны быть обнуляемыми. тогда это сработает.
Ответ №4:
Как сообщает @dbc в комментариях:
- При десериализации:
Если ваша модель обладает свойством, которого нет в вашем JSON, и вы хотите, чтобы это было ошибкой, используйте
[JsonProperty(Required = Required.Always)]
.
- При сериализации:
Если ваш JSON обладает свойством, которого нет у вашей Модели, и вы хотите, чтобы это было ошибкой, используйте
MissingMemberHandling = MissingMemberHandling.Error
.
также использование [DataMember(IsRequired = true)]
для ошибки при десериализации является верным, когда тип proeprty обнуляемый.
Ответ №5:
Просто определите свои члены в вашем классе definition с вопросительным знаком ‘?’ int?
:
private class MyJsonObjView
{
[JsonProperty("MyJsonInt")]
public int? MyJsonInt { get; set; }
}
Когда оно не инициализировано, оно просто будет null
, в противном случае это будет допустимое значение. Это позволяет вам иметь необязательные настройки и оценивать их на основе каждой настройки.
Комментарии:
1. Это не может определить разницу между тем, когда свойство отсутствует или установлено в null в JSON.