Определить, отсутствует ли у десериализованного объекта поле с классом JsonConvert в Json.NET

#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.