using System.Net.Http.Headers;
using static System.Math;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Net.Http.Json;
using System.Net;
using HttpClient client = new();
await ProcessRepositoriesAsync(client);
static async Task ProcessRepositoriesAsync(HttpClient client)
{
string apiUrl = "<<API CALL URL WITH AUTHENTICATION KEY>>";
try
{
string jsonResponse = await client.GetStringAsync(apiUrl);
var jsonDocument = JsonDocument.Parse(jsonResponse);
if (jsonDocument.RootElement.TryGetProperty("response", out var responseData))
{
string jsonContent = File.ReadAllText(responseData.ToString());
List<FlightData> flightList = JsonSerializer.Deserialize<List<FlightData>>(jsonContent);
foreach (var flight in flightList)
{
Console.WriteLine($"Flight Number: {flight.flag}, Altitude: {flight.alt}");
}
}
else
{
Console.WriteLine("No 'response' field found in JSON.");
}
}
catch (HttpRequestException ex)
{
Console.WriteLine($"Error: {ex.Message}");
}
catch (JsonException ex)
{
Console.WriteLine($"JSON Deserialization Error: {ex.Message}");
}
}
internal class FlightData
{
public string? hex { get; set; }
public string? reg_number { get; set; }
public string? flag { get; set; }
public string? lat { get; set; }
public string? lng { get; set; }
public string? alt { get; set; }
public string? dir { get; set; }
public string? speed { get; set; }
public string? v_speed { get; set; }
public string? squawk { get; set; }
public string? flight_number { get; set; }
public string? flight_icao { get; set; }
public string? flight_iata { get; set; }
public string? dep_icao { get; set; }
public string? dep_iata { get; set; }
public string? airline_icao { get; set; }
public string? airline_iata { get; set; }
public string? aircraft_icao { get; set; }
public string? updated { get; set; }
public string? status { get; set; }
public FlightData(string hex, string reg_number, string flag, string lat, string lng, string alt, string dir, string speed, string v_speed, string flight_number, string flight_icao, string flight_iata, string dep_icao, string dep_iata, string airline_icao,
string airline_iata, string aircraft_icao, string updated, string status)
{
this.hex = hex;
this.reg_number = reg_number;
this.flag = flag;
this.lat = lat;
this.lng = lng;
this.alt = alt;
this.dir = dir;
this.speed = speed;
this.v_speed = v_speed;
this.flight_number = flight_number;
this.flight_icao = flight_icao;
this.flight_iata = flight_iata;
this.dep_icao = dep_icao;
this.dep_iata = dep_iata;
this.airline_icao = airline_icao;
this.airline_iata = airline_iata;
this.aircraft_icao = aircraft_icao;
this.updated = updated;
this.status = status;
}
}
(Мне также не нужно и не нужно КАЖДОЕ отдельное свойство, которое есть в конструкторе. Я просто добавил все, чтобы посмотреть, поможет ли это.) Код может быть немного шатким и выглядеть не очень хорошо. Я успешно сделал это на Python, но мне нужно сделать это на C#. Все это в новинку для меня, и я часами изучал документацию Microsoft, YouTube, GitHub, StackOverflow и т. д.
Я вызываю API, который дает мне данные о полете в реальном времени в ответе JSON. Мой план состоит в том, чтобы взять это и преобразовать каждую запись JSON в объект FlightData. Проблема, с которой я столкнулся (я думаю), заключается в том, что в верхней части ответа JSON содержится тонна метаданных. Меня это не волнует, пока не будет написано «ответ», после чего будут мои данные. Я думаю, что он пытается разобрать метаданные в объект и попадает во вторую ловушку, потому что атрибуты не совпадают. Оператор if помогает мне пройти мимо этого, но тогда он не работает должным образом. Это зависает мой компьютер. Я успешно вызвал API и получил данные.
В питоне все, что я сделал, было
allPlanes = json.loads(data)
for i in allPlanes['response']:
try: ....
и это сработало хорошо.
Я ценю любую помощь и прошу прощения, если плохо объяснил. Если я выдам важную информацию, пожалуйста, не стесняйтесь сказать мне.
Я пробовал так много разных методов, найденных в Интернете, и решение, упомянутое выше, является самым близким, которое я получил. Я знаю, что оператор if работает, потому что я вывел его в .txt, и он разделил метаданные и ответ, который мне действительно нужен.
Обновлено: вот в чем ошибка, когда она попадает во второй улов:
Ошибка десериализации JSON: значение JSON не может быть преобразовано в FlightData. Путь: $[0].lat | Номер строки: 0 | Байтпозитионинлайн: 68.
Редактировать 2: спасибо за быстрые ответы, ребята. Не знаю, как я забыл добавить образец JSON.
Вот один без заголовка/метаданных (честно говоря, я не уверен, что это за точный термин):
[
{
"hex":"142329",
"reg_number":"RA-09001",
"flag":"RU",
"lat":56.33128,
"lng":79.944679,
"alt":10980,
"dir":272,
"speed":872,
"v_speed":0,
"squawk":"5257",
"flight_number":"9634",
"flight_icao":"GZP9634",
"flight_iata":"4G9634",
"dep_icao":"UNTT",
"dep_iata":"TOF",
"airline_icao":"GZP",
"airline_iata":"4G",
"aircraft_icao":"F900",
"updated":1692074910,
"status":"en-route"
},
{
"hex":"152000",
"reg_number":"RA-73728",
"flag":"RU",
"lat":56.401016,
"lng":45.294384,
"alt":10355,
"dir":260,
"speed":779,
"v_speed":0,
"squawk":"5527",
"flight_number":"1437",
"flight_icao":"AFL1437",
"flight_iata":"SU1437",
"dep_icao":"USSS",
"dep_iata":"SVX",
"arr_icao":"UUEE",
"arr_iata":"SVO",
"airline_icao":"AFL",
"airline_iata":"SU",
"aircraft_icao":"A321",
"updated":1692074910,
"status":"en-route"
}
]
А вот верхняя часть с записью:
{
"request":{
"lang":"en",
"currency":"USD",
"time":33,
"id":"6u6cys0kh2o",
"server":"l",
"host":"airlabs.co",
"pid":1867027,
"key":{
"id":26237,
"api_key":"2354963e-6fc3-4226-a220-46cb2bab6633",
"type":"free",
"expired":"2023-09-10T00:00:00.000Z",
"registered":"2023-08-11T04:11:07.000Z",
"limits_by_hour":2500,
"limits_by_minute":250,
"limits_by_month":1000,
"limits_total":884
},
"params":{
"lang":"en"
},
"version":9,
"method":"flights",
"client":{
"ip":"2600:6c5c:6c00:4d9:804e:66ab:1add:d35",
"geo":{
"country_code":"US",
"country":"United States",
"continent":"North America",
"city":"Kingsport",
"lat":36.5491,
"lng":-82.5584,
"timezone":"America/New_York"
},
"connection":{
"isp_code":20115,
"isp_name":"Charter Communications"
},
"device":{
},
"agent":{
},
"karma":{
"is_blocked":false,
"is_crawler":false,
"is_bot":false,
"is_friend":false,
"is_regular":true
}
}
},
"response":[
{
"hex":"142329",
"reg_number":"RA-09001",
"flag":"RU",
"lat":56.307404,
"lng":81.793709,
"alt":10492,
"dir":268,
"speed":861,
"v_speed":3.3,
"squawk":"5257",
"flight_number":"9634",
"flight_icao":"GZP9634",
"flight_iata":"4G9634",
"dep_icao":"UNTT",
"dep_iata":"TOF",
"airline_icao":"GZP",
"airline_iata":"4G",
"aircraft_icao":"F900",
"updated":1692074433,
"status":"en-route"
},
{
"hex":"152000",
"reg_number":"RA-73728",
"flag":"RU",
"lat":56.593597,
"lng":46.8978,
"alt":10363,
"dir":250,
"speed":759,
"v_speed":0,
"squawk":"5527",
"flight_number":"1437",
"flight_icao":"AFL1437",
"flight_iata":"SU1437",
"dep_icao":"USSS",
"dep_iata":"SVX",
"arr_icao":"UUEE",
"arr_iata":"SVO",
"airline_icao":"AFL",
"airline_iata":"SU",
"aircraft_icao":"A321",
"updated":1692074433,
"status":"en-route"
}
]
}
А поскольку вы используете геттеры и сеттеры для FlightData, вам не нужен конструктор с параметрами.
Просто из любопытства - правильно ли я понимаю, что вы запрашиваете какой-то API, а затем читаете локальный файл на основе ответа?
Что касается проблемы - просто предположение - public string? lat { get; set; } должно быть что-то вроде public double? lat { get; set; }. System.Text.Json довольно требователен к используемым правильным типам (т. е. он не будет считывать числа в строки по умолчанию). Ошибка предполагает, что существует несоответствие типов. P.S. пожалуйста, предоставьте образец JSON (т.е. минимальный воспроизводимый пример)
Добавил JSON. Извините за это, ребята. Спасибо за ответы.
@GuruStron Честно говоря, я не знаком с терминологией. Я вызываю API, и он возвращает гигантский ответ, полный текста. Я не думаю, что это файл?
@Chris Здесь не так много терминологии. У вас есть string jsonContent = File.ReadAllText(responseData.ToString()); в вашем коде. File.ReadAllText будет читать текст из ... файла =)
@GuruStron Понятно. Эта часть кода была еще одной попыткой попробовать что-то другое. Когда я использую его, он зависает vsstudio. Когда я удаляю его, я получаю ошибки JSON. Что, если я превращу все это в гигантскую строку и разделю/обрежу на основе запятых и скобок/скобок?





Итак, если предположить, что второй JSON является строкой ответа, вам нужно исправить типы в целевом классе (как я писал в комментариях):
public class FlightData
{
[JsonPropertyName("hex")]
public string Hex { get; set; }
[JsonPropertyName("reg_number")]
public string RegNumber { get; set; }
[JsonPropertyName("flag")]
public string Flag { get; set; }
[JsonPropertyName("lat")]
public double Lat { get; set; }
[JsonPropertyName("lng")]
public double Lng { get; set; }
[JsonPropertyName("alt")]
public long Alt { get; set; }
[JsonPropertyName("dir")]
public long Dir { get; set; }
[JsonPropertyName("speed")]
public long Speed { get; set; }
[JsonPropertyName("v_speed")]
public double VSpeed { get; set; }
[JsonPropertyName("squawk")]
public string Squawk { get; set; }
[JsonPropertyName("flight_number")]
public string FlightNumber { get; set; }
[JsonPropertyName("flight_icao")]
public string FlightIcao { get; set; }
[JsonPropertyName("flight_iata")]
public string FlightIata { get; set; }
[JsonPropertyName("dep_icao")]
public string DepIcao { get; set; }
[JsonPropertyName("dep_iata")]
public string DepIata { get; set; }
[JsonPropertyName("airline_icao")]
public string AirlineIcao { get; set; }
[JsonPropertyName("airline_iata")]
public string AirlineIata { get; set; }
[JsonPropertyName("aircraft_icao")]
public string AircraftIcao { get; set; }
[JsonPropertyName("updated")]
public long Updated { get; set; }
[JsonPropertyName("status")]
public string Status { get; set; }
[JsonPropertyName("arr_icao")]
public string ArrIcao { get; set; }
[JsonPropertyName("arr_iata")]
public string ArrIata { get; set; }
}
И затем вы можете ввести Root и просто использовать его:
class Root
{
[JsonPropertyName("response")]
public List<FlightData> Response { get; set; }
}
И использование:
var deserialize = JsonSerializer.Deserialize<Root>(jsonResponse);
Или просто:
var result = await client.GetFromJsonAsync<Root>(...)
Если вы непреклонны в проверке собственности, используйте:
using var jsonDocument = JsonDocument.Parse(jsonResponse); // DO NOT FORGET USING!
if (jsonDocument.RootElement.TryGetProperty("response", out var responseData))
{
var result = responseData.Deserialize<List<FlightData>>();
}
P.S.
Существует множество инструментов, позволяющих преобразовывать JSON в типы C#, некоторые из них встроены в IDE, или вы можете использовать онлайн-инструменты, такие как app.quicktype.io
Это сработало чудесно. Я очень ценю это! Я был на этом в течение нескольких часов. Если бы я хотел прочитать о том, что решило проблему, что бы я искал? Кроме того, это не связано, но очень быстро. В некоторых записях в JSON отсутствуют определенные поля, например, может отсутствовать шестнадцатеричный код или любая комбинация. Поскольку свойства FlightData могут принимать значения NULL, он просто оставит их пустыми и заполнит то, что может, с помощью Json Deserialize?
@Chris был рад помочь! Не уверен, что это описано в документации, TBH. «он просто оставит эти пустые и заполнит то, что может, с помощью Json» - да, сериализатор будет использовать значение по умолчанию (обратите внимание, что для таких типов значений, как int, вам может потребоваться использовать их аналог, допускающий значение NULL - int?, поиск типов значений, допускающих значение NULL ). Также обратите внимание, что вы также можете использовать Newtonsoft Json.NET, который долгое время был стандартом де-факто.
Добавление образца
jsonтакже было бы неплохо.