Не удается преобразовать из JValue в JObject

У меня есть следующий класс со статическим методом,

public static class RouteSerializer
{
    public static string SerializeRouteInformation(string content)
    {
        RouteMapModel routeMapModel = new RouteMapModel();
        List<RouteMapModel.end_location> endLocationList = new List<RouteMapModel.end_location>();

        var obj = JObject.Parse(content);

        string objRoutes = obj["routes"].ToString();

        JArray routeArray = JArray.Parse(objRoutes);

        JArray legArray = new JArray();
        foreach (JObject item in routeArray)
        {
            string leg = item.GetValue("legs").ToString();                
            legArray.Add(leg);
        }

        JArray stepArray = new JArray();
        foreach (JObject item in legArray)
        {
            string step = item.GetValue("steps").ToString();
            stepArray.Add(step);
        }

        foreach(JObject item in stepArray)
        {
            string endLocation = item.GetValue("end_location").ToString();
            var serializedEndLocation = JsonConvert.DeserializeObject<RouteMapModel.end_location>(endLocation);
            endLocationList.Add(serializedEndLocation);
        }

        //... goes on
    }
}

Но я получил ошибку при выпрашивании второго foreach как говорится Newtonsoft.Json.Linq.JValue cannot be assigned to Newtonsoft.Json.Linq.JObject. Но проблема в том, что если я изменил тип элемента с JObject на JValue в последних предложениях foreach, я не смогу получить доступ к методу .GetValue(), поскольку JValue не включает его.

Ниже приведена строка JSON, на которой я играю,

    { "geocoded_waypoints" : [
      {
         "geocoder_status" : "OK",
         "place_id" : "ChIJ5cGzCGa4yhQRk-lsJUoyizk",
         "types" : [ "street_address" ]
      },
      {
         "geocoder_status" : "OK",
         "place_id" : "ChIJb5VnEF64yhQRCrgps2g77jc",
         "types" : [ "street_address" ]
      }
   ],
"routes" : [
      {
         "bounds" : {
            "northeast" : {
               "lat" : 40.990381,
               "lng" : 29.0282547
            },
            "southwest" : {
               "lat" : 40.9863897,
               "lng" : 29.0216118
            }
         },
         "copyrights" : "Harita verileri ©2019 Google",
         "legs" : [
            {
               "distance" : {
                  "text" : "0,9 km",
                  "value" : 894
               },
               "duration" : {
                  "text" : "11 dakika",
                  "value" : 655
               },
               "end_address" : "Caferağa Mahallesi, Tuğlacı Eminbey Cd. No:5, 34710 Kadıköy/İstanbul, Türkiye",
               "end_location" : {
                  "lat" : 40.9863897,
                  "lng" : 29.0218105
               },
               "start_address" : "Osmanağa Mahallesi, Serasker Cd. No:118, 34714 Kadıköy/İstanbul, Türkiye",
               "start_location" : {
                  "lat" : 40.9893375,
                  "lng" : 29.028225
               },
               "steps" : [
                  {
                     "distance" : {
                        "text" : "8 m",
                        "value" : 8
                     },
                     "duration" : {
                        "text" : "1 dakika",
                        "value" : 5
                     },
                     "end_location" : {
                        "lat" : 40.9894537,
                        "lng" : 29.0282117
                     },
                     "html_instructions" : "\u003cb\u003eZiya Bey Sk.\u003c/b\u003e adlı yerden \u003cb\u003eSerasker Cd.\u003c/b\u003e hedefine \u003cb\u003ekuzey\u003c/b\u003e yönünde ilerleyin",
                     "polyline" : {
                        "points" : "kvdyFkqdpDGCMA?F"
                     },
                     "start_location" : {
                        "lat" : 40.9893375,
                        "lng" : 29.028225
                     },
                     "travel_mode" : "WALKING"
                  },
                  {
                     "distance" : {
                        "text" : "0,3 km",
                        "value" : 326
                     },
                     "duration" : {
                        "text" : "4 dakika",
                        "value" : 215
                     },
                     "end_location" : {
                        "lat" : 40.990381,
                        "lng" : 29.024582
                     },
                     "html_instructions" : "\u003cb\u003eSerasker Cd.\u003c/b\u003e yönünde \u003cb\u003esola\u003c/b\u003e dönün",
                     "maneuver" : "turn-left",
                     "polyline" : {
                        "points" : "awdyFiqdpDMxAKr@OjACP[vCEPC^Cf@CLAHENMZ@LQf@Qd@KZENSj@"
                     },
                     "start_location" : {
                        "lat" : 40.9894537,
                        "lng" : 29.0282117
                     },
                     "travel_mode" : "WALKING"
                  },
                  {
                     "distance" : {
                        "text" : "34 m",
                        "value" : 34
                     },
                     "duration" : {
                        "text" : "1 dakika",
                        "value" : 25
                     },
                     "end_location" : {
                        "lat" : 40.9901185,
                        "lng" : 29.0243691
                     },
                     "html_instructions" : "\u003cb\u003eMühürdar Cd.\u003c/b\u003e yönünde \u003cb\u003esola\u003c/b\u003e dönün",
                     "maneuver" : "turn-left",
                     "polyline" : {
                        "points" : "{|dyFszcpDHFHF^X"
                     },
                     "start_location" : {
                        "lat" : 40.990381,
                        "lng" : 29.024582
                     },
                     "travel_mode" : "WALKING"
                  },
                  {
                     "distance" : {
                        "text" : "8 m",
                        "value" : 8
                     },
                     "duration" : {
                        "text" : "1 dakika",
                        "value" : 5
                     },
                     "end_location" : {
                        "lat" : 40.990081,
                        "lng" : 29.0242851
                     },
                     "html_instructions" : "\u003cb\u003eMühürdar Cd.\u003c/b\u003e yönünde hafif \u003cb\u003esağa\u003c/b\u003e yönelin",
                     "maneuver" : "turn-slight-right",
                     "polyline" : {
                        "points" : "g{dyFiycpD?D?@?@@??@DB"
                     },
                     "start_location" : {
                        "lat" : 40.9901185,
                        "lng" : 29.0243691
                     },
                     "travel_mode" : "WALKING"
                  },
                  {
                     "distance" : {
                        "text" : "7 m",
                        "value" : 7
                     },
                     "duration" : {
                        "text" : "1 dakika",
                        "value" : 6
                     },
                     "end_location" : {
                        "lat" : 40.9900274,
                        "lng" : 29.0243112
                     },
                     "html_instructions" : "\u003cb\u003eMuvakkıthane Cd.\u003c/b\u003e konumunda \u003cb\u003esola\u003c/b\u003e dönün",
                     "maneuver" : "turn-left",
                     "polyline" : {
                        "points" : "_{dyFyxcpDDABA"
                     },
                     "start_location" : {
                        "lat" : 40.990081,
                        "lng" : 29.0242851
                     },
                     "travel_mode" : "WALKING"
                  },
                  {
                     "distance" : {
                        "text" : "0,4 km",
                        "value" : 352
                     },
                     "duration" : {
                        "text" : "4 dakika",
                        "value" : 259
                     },
                     "end_location" : {
                        "lat" : 40.987586,
                        "lng" : 29.0217648
                     },
                     "html_instructions" : "\u003cb\u003eMühürdar Cd.\u003c/b\u003e yönünde \u003cb\u003esağa\u003c/b\u003e dönün",
                     "maneuver" : "turn-right",
                     "polyline" : {
                        "points" : "uzdyF}xcpDhAz@pA|@pBtAHRJHRPPNPX\\d@BDHKfAlBDLDHDN@LBN"
                     },
                     "start_location" : {
                        "lat" : 40.9900274,
                        "lng" : 29.0243112
                     },
                     "travel_mode" : "WALKING"
                  },
                  {
                     "distance" : {
                        "text" : "63 m",
                        "value" : 63
                     },
                     "duration" : {
                        "text" : "1 dakika",
                        "value" : 51
                     },
                     "end_location" : {
                        "lat" : 40.987087,
                        "lng" : 29.0216118
                     },
                     "html_instructions" : "\u003cb\u003eMühürdar Cd.\u003c/b\u003e boyunca ilerlemek için \u003cb\u003esola\u003c/b\u003e dönün",
                     "maneuver" : "turn-left",
                     "polyline" : {
                        "points" : "mkdyF_icpDNBJ@J@TBJ?JADA@DDN"
                     },
                     "start_location" : {
                        "lat" : 40.987586,
                        "lng" : 29.0217648
                     },
                     "travel_mode" : "WALKING"
                  },
                  {
                     "distance" : {
                        "text" : "74 m",
                        "value" : 74
                     },
                     "duration" : {
                        "text" : "1 dakika",
                        "value" : 64
                     },
                     "end_location" : {
                        "lat" : 40.9864708,
                        "lng" : 29.0216118
                     },
                     "html_instructions" : "\u003cb\u003eMühürdar Cd.\u003c/b\u003e boyunca ilerlemek için \u003cb\u003esola\u003c/b\u003e dönün",
                     "maneuver" : "turn-left",
                     "polyline" : {
                        "points" : "ihdyFahcpDJEJAFALAH?VBj@F"
                     },
                     "start_location" : {
                        "lat" : 40.987087,
                        "lng" : 29.0216118
                     },
                     "travel_mode" : "WALKING"
                  },
                  {
                     "distance" : {
                        "text" : "22 m",
                        "value" : 22
                     },
                     "duration" : {
                        "text" : "1 dakika",
                        "value" : 25
                     },
                     "end_location" : {
                        "lat" : 40.9863897,
                        "lng" : 29.0218105
                     },
                     "html_instructions" : "\u003cb\u003eTuğlacı Eminbey Cd.\u003c/b\u003e yönünde \u003cb\u003esola\u003c/b\u003e dönün",
                     "maneuver" : "turn-left",
                     "polyline" : {
                        "points" : "mddyFahcpDNg@"
                     },
                     "start_location" : {
                        "lat" : 40.9864708,
                        "lng" : 29.0216118
                     },
                     "travel_mode" : "WALKING"
                  }
               ],
               "traffic_speed_entry" : [],
               "via_waypoint" : []
            }
         ],
         "overview_polyline" : {
            "points" : "kvdyFkqdpDUEM`B{@hHQfBGXMZ@Lc@lAQj@Sj@HFHF^X?D?B@@DBDABAhAz@bErCHRJHd@`@n@~@BDHKlAzBJXD\\ZD`@DVADA@DDNJERCVAbAJNg@"
         },
         "summary" : "Serasker Cd. ve Mühürdar Cd.",
         "warnings" : [
            "Yürüyerek gitmek için yol tarifi beta özelliğinde mevcuttur. Dikkat – Bu rotada kaldırım veya yaya yolu olmayabilir."
         ],
         "waypoint_order" : []
      }
   ],
   "status" : "OK"
}

Я не предпочитаю десериализовать весь объект, так как служба не будет использовать почти все эти свойства, кроме "legs", "steps" и "end_location", которые находятся внутри "steps".

«Я не предпочитаю десериализовать весь объект» — Вы усложняете задачу больше, чем она должна быть. JObject.Parse(content) уже десериализует все это. Просто пройдите по графу объектов вместо преобразования обратно в строку и повторного анализа.
madreflection 19.02.2019 17:45
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
1
7 424
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Проблема заключается в том, что ваш код для запроса выбранных частей иерархии JObject obj многократно преобразует туда и обратно из JToken в строковые представления JSON, и в какой-то момент вместо повторный разбор строки JSON вы просто используете ее как строковый литерал.

В частности, проблема связана со следующим кодом:

JArray legArray = new JArray();
foreach (JObject item in routeArray)
{
    string leg = item.GetValue("legs").ToString();
    legArray.Add(leg);
}

Вы вызываете JArray.Add(), но этот метод имеет несколько перегрузок, так какая из них вызывается? Поскольку существует неявный оператор от string до JToken, происходит следующее: строка leg преобразуется в строковый литерал JValue с помощью неявного оператора, который, в свою очередь, добавляется к JArray. После этого следующий код завершается ошибкой с недопустимым исключением приведения, поскольку элементы, которые вы добавили в legArray, относятся к типу JValue, а не JObject:

foreach (JObject item in legArray)
{

Решение предназначен для упрощения вашего кода и полного исключения преобразования туда и обратно между представлениями string и JToken. Следующий код делает свое дело:

var endLocationList = obj
    .SelectTokens("routes[*].legs[*].steps[*].end_location")
    .Select(t => t.ToObject<Location>())
    .ToList();

Использование типа

public class Location
{
    public double Lat { get; set; }
    public double Lng { get; set; }
}

Примечания:

  • Вы можете десериализовать напрямую из JToken в POCO, используя JToken.ToObject<T>(). Это проще и эффективнее, чем форматирование JToken в виде строки с последующей десериализацией строки.

  • JToken.SelectTokens() позволяет запрашивать иерархию JSON, используя Синтаксис JSONPath.

    Здесь [*] представляет собой подстановочный знак, выбирающий все элементы в массиве, в частности массивы "routes", "legs" и "steps".

    Для получения дополнительной информации см. # JSONPath — XPath для JSON.

Демонстрационная рабочий пример здесь.

это отлично работает на моей локальной машине, и моя модель возврата выглядит так [{"Legs":[{"Steps":[{"EndLocation":[{"Lat":41.0917854,"Lng":‌​29.0938952},{"Lat":4‌​1.0927256,"Lng":29.0‌​943774},{"Lat":41.09‌​31956,"Lng":29.09484‌​8},{"Lat":41.0944882‌​99999988,"Lng":29.09‌​52805},{"Lat":41.094‌​5246,"Lng":29.095436‌​2},{"Lat":41.0945706‌​,"Lng":29.0955857},{‌​"Lat":41.09436549999‌​9988,"Lng":29.096718‌​7}]}]}]}] Но после того, как я публикую этот проект API на сервере и отправляю тот же запрос методу, который возвращает эту модель, он возвращает модель без заполнения списка EndLocation.

RaZzLe 24.02.2019 21:13

Живой проект возвращает это: [{"Legs":[{"Steps":[{"EndLocation":[]}]}]}] Странно то, что я также тестировал на другом сервере, и он заполняет модель так, как предполагалось. Вы хоть представляете, как это могло произойти?

RaZzLe 24.02.2019 21:14

@RaZzLe - нужно увидеть минимальный воспроизводимый пример, но, может быть, вы не настраиваете свой сервер для использования верблюжьего регистра? См., возможно, Как я могу вернуть camelCase JSON, сериализованный JSON.NET, из методов контроллера ASP.NET MVC? или Веб-API asp.net core 1.0 использует верблюжий регистр.

dbc 26.02.2019 22:28

Другие вопросы по теме