C # JsonSerializer.Десериализация массива

#c# #json

#c# #json

Вопрос:

Все,

Редактировать: Во-первых, спасибо всем за помощь. Во-вторых, я новичок в Stack Overflow, поэтому прошу прощения, если я неправильно добавил это редактирование.

После комментариев и ответов я обновил свою структуру классов до:

класс служб:

 using System;
using System.Collections.Generic;
using System.Text;
using System.Text.Json;

namespace RTT_API
{
    class services
    {
        public List<service> service = new List<service>();

        public services()
        {

        }
    }
}
 

Класс обслуживания:

 
using System;
using System.Collections.Generic;
using System.Text;

namespace RTT_API
{
    class service
    {
        public string atocCode{get; set;}

        public service()
        {

        }
    }
}
 

К сожалению, я все еще получаю ту же ошибку. Я думаю, что я все еще не совсем сопоставил свою структуру классов со структурой JSON? К сожалению, я не уверен, в чем моя ошибка. Если это поможет выявить мою ошибку с помощью сравнения, тогда работает следующее:

Класс местоположения

 using System; 
using System.Collections.Generic;
using System.Text;

namespace RTT_API
{
    class location
    {
        public string name { get; set; }
        public string crs { get; set; }

        public location()
        {
            
        }
    }
}
 

Команда десериализации местоположения и тестовый вывод:

 location locations = JsonSerializer.Deserialize<location>(channelResponse.RootElement.GetProperty("location").GetRawText());

MessageBox.Show(locations.crs);

 

Оригинальный вопрос:

Мой JSON выглядит следующим образом:

 {
   "location": {
       "name": "Bournemouth",
       "crs": "BMH",
       "tiploc": "BOMO"
   },
   "filter": null,
   "services": [
       {
           "locationDetail": {
               "realtimeActivated": true,
               "tiploc": "BOMO",
               "crs": "BMH",
               "description": "Bournemouth",
               "wttBookedArrival": "011630",
               "wttBookedDeparture": "011830",
               "gbttBookedArrival": "0117",
               "gbttBookedDeparture": "0118",
               "origin": [
                   {
                       "tiploc": "WATRLMN",
                       "description": "London Waterloo",
                       "workingTime": "230500",
                       "publicTime": "2305"
                   }
               ],
               "destination": [
                   {
                       "tiploc": "POOLE",
                       "description": "Poole",
                       "workingTime": "013000",
                       "publicTime": "0130"
                   }
               ],
               "isCall": true,
               "isPublicCall": true,
               "realtimeArrival": "0114",
               "realtimeArrivalActual": false,
               "realtimeDeparture": "0118",
               "realtimeDepartureActual": false,
               "platform": "3",
               "platformConfirmed": false,
               "platformChanged": false,
               "displayAs": "CALL"
           },
           "serviceUid": "W90091",
           "runDate": "2013-06-11",
           "trainIdentity": "1B77",
           "runningIdentity": "1B77",
           "atocCode": "SW",
           "atocName": "South West Trains",
           "serviceType": "train",
           "isPassenger": true
       }
   ]
}
 

My class structure is as follows:

servicelist class:

 using System;
using System.Collections.Generic;
using System.Text;
using System.Text.Json;

namespace RTT_API
{
    class servicelist
    {
        public List<services> service = new List<services>();

        public servicelist()
        {

        }
    }
}
 

класс служб:

 using System;
using System.Collections.Generic;
using System.Text;

namespace RTT_API
{
    class services
    {
        public int serviceUid;

        public services()
        {

        }

    }
}

 

Для десериализации я попытался:

 services servicelist = JsonSerializer.Deserialize<services>(channelResponse.RootElement.GetProperty("services").GetRawText());
 

и

 servicelist servicelist = JsonSerializer.Deserialize<servicelist>(channelResponse.RootElement.GetProperty("services").GetRawText());;
 

В обоих случаях я получаю ‘System.Text.Json.Исключение JSONException’

Я думаю, что существует несоответствие между структурой классов и JSON, но я не могу понять, в чем проблема? Я впервые пытаюсь десериализовать массив.

Спасибо

 using System; 
using System.Collections.Generic;
using System.Text;

namespace RTT_API
{
    class location
    {
        public string name { get; set; }
        public string crs { get; set; }

        public location()
        {
            
        }
    }
}

 

Ответ №1:

Вы можете генерировать точные классы C # в соответствии с вашим JSON, используя инструменты именно для этой цели. Я использовал https://json2csharp.com / , другой — это https://jsonutils.com / — это веб-сервисы, которые не требуют установки на компьютер, другой вариант — создание классов через Visual Studio (с установленными Web Essentials), там вы должны использовать Edit — Paste special — вставить JSON в качестве класса.

Как только у вас есть допустимые классы (я вставил сгенерированные классы ниже), вы можете десериализовать весь корневой объект, а затем получить доступ к любой его части, включая services часть:

     // jsonInputText holds entire JSON string you posted
    Root root = JsonSerializer.Deserialize<Root>(jsonInputText);
    List<Service> serviceList = root.services;
 

Сгенерированные классы:

 public class Location
{
    public string name { get; set; }
    public string crs { get; set; }
    public string tiploc { get; set; }
}

public class Origin
{
    public string tiploc { get; set; }
    public string description { get; set; }
    public string workingTime { get; set; }
    public string publicTime { get; set; }
}

public class Destination
{
    public string tiploc { get; set; }
    public string description { get; set; }
    public string workingTime { get; set; }
    public string publicTime { get; set; }
}

public class LocationDetail
{
    public bool realtimeActivated { get; set; }
    public string tiploc { get; set; }
    public string crs { get; set; }
    public string description { get; set; }
    public string wttBookedArrival { get; set; }
    public string wttBookedDeparture { get; set; }
    public string gbttBookedArrival { get; set; }
    public string gbttBookedDeparture { get; set; }
    public List<Origin> origin { get; set; }
    public List<Destination> destination { get; set; }
    public bool isCall { get; set; }
    public bool isPublicCall { get; set; }
    public string realtimeArrival { get; set; }
    public bool realtimeArrivalActual { get; set; }
    public string realtimeDeparture { get; set; }
    public bool realtimeDepartureActual { get; set; }
    public string platform { get; set; }
    public bool platformConfirmed { get; set; }
    public bool platformChanged { get; set; }
    public string displayAs { get; set; }
}

public class Service
{
    public LocationDetail locationDetail { get; set; }
    public string serviceUid { get; set; }
    public string runDate { get; set; }
    public string trainIdentity { get; set; }
    public string runningIdentity { get; set; }
    public string atocCode { get; set; }
    public string atocName { get; set; }
    public string serviceType { get; set; }
    public bool isPassenger { get; set; }
}

public class Root
{
    public Location location { get; set; }
    public object filter { get; set; }
    public List<Service> services { get; set; }
}
 

Комментарии:

1. Спасибо за вашу помощь. Я ценю информацию об онлайн-инструментах. Мне было бы интересно узнать, почему мое определение не сработало, если это возможно. Я обновил свое определение serviceUID до общедоступной строки serviceUid { get; set; }, но это все еще не сработало.

2. Нет проблем. Классы должны соответствовать структуре JSON. В строке JSON в свойстве «services» у вас есть массив JSON — это означает, что в свойстве класса «services» должна быть коллекция (Список<>) объектов «service», эти объекты «service» представлены сгенерированным классом Service. Объект Service должен иметь определенные свойства, такие как «locationDetail» и т.д., После последовательной реализации объектов и коллекций ошибок быть не должно — самый простой способ создать правильный класс — использовать некоторые генераторы JSON-to-class . До тех пор, пока структура класса не совпадает, могут возникать ошибки.

3. Еще раз спасибо. Я обновил свой код и вопрос. Я новичок в StackOverflow, так что, надеюсь, это было правильно.

4. Это лучший способ; большое спасибо за советы!

Ответ №2:

Если вам нужно десериализовать только часть вашего json, вы можете использовать JObject JToken для этого вспомогательные классы и .

 var json = File.ReadAllText("Sample.json");
JObject topLevelObject = JObject.Parse(json);
JToken servicesToken = topLevelObject["services"];
var services = servicesToken.ToObject<List<Service>>();
 
  • topLevelObject Содержит весь json в полуразработанном формате.
  • Вы можете использовать оператор индексатора для извлечения объекта / массива с помощью одного из ключей верхнего уровня.
  • На a JToken вы можете вызвать ToObject<T> десериализацию данных в пользовательский класс данных.

Чтобы иметь возможность анализировать ваш json, мне пришлось настроить services тип, потому W90091 что as serviceUid не может быть проанализирован как int . Итак, вот мое Service определение класса:

 public class Service
{
    public string ServiceUid;
}
 

Здесь следует отметить, что в данном случае корпус не имеет значения, поэтому, пожалуйста, используйте camelCasing в ваших доменных моделях, как вы обычно делаете в C #.

Комментарии:

1. Спасибо за совет. Это полезно.

Ответ №3:

Спасибо всем за помощь.

Во-первых, мне пришлось внести несколько изменений в имена классов, поскольку они не соответствовали JSON. Мне также пришлось изменить синтаксис двух команд, которые я подробно описал ниже:

Я изменил определение списка объектов с:

 public List<services> service = new List<services>();
 

Для:

 public List<service> destination { get; set; };
 

и команда десериализации из:

 services servicelist = JsonSerializer.Deserialize<services>(channelResponse.RootElement.GetProperty("services").GetRawText());
 

Для

 var servicelist = JsonSerializer.Deserialize<List<service>>(channelResponse.RootElement.GetProperty("services").GetRawText());
 

Переход с сервисов на var может быть не лучшим решением. Я думаю, что это первое изменение и сопоставление имен классов с JSON, которое в корне устранило проблему.