У меня есть следующий класс со статическим методом,
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 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":41.0927256,"Lng":29.0943774},{"Lat":41.0931956,"Lng":29.094848},{"Lat":41.094488299999988,"Lng":29.0952805},{"Lat":41.0945246,"Lng":29.0954362},{"Lat":41.0945706,"Lng":29.0955857},{"Lat":41.094365499999988,"Lng":29.0967187}]}]}]}] Но после того, как я публикую этот проект API на сервере и отправляю тот же запрос методу, который возвращает эту модель, он возвращает модель без заполнения списка EndLocation.
Живой проект возвращает это: [{"Legs":[{"Steps":[{"EndLocation":[]}]}]}] Странно то, что я также тестировал на другом сервере, и он заполняет модель так, как предполагалось. Вы хоть представляете, как это могло произойти?
@RaZzLe - нужно увидеть минимальный воспроизводимый пример, но, может быть, вы не настраиваете свой сервер для использования верблюжьего регистра? См., возможно, Как я могу вернуть camelCase JSON, сериализованный JSON.NET, из методов контроллера ASP.NET MVC? или Веб-API asp.net core 1.0 использует верблюжий регистр.
JObject.Parse(content)уже десериализует все это. Просто пройдите по графу объектов вместо преобразования обратно в строку и повторного анализа.