question

marcwheeler avatar image
0 Votes"
marcwheeler asked TimonYang-MSFT commented

JSON.NET Populate Textboxes w/ Specific Values

Hello all,

I am very new to json and after days of searching the internet and reading articles to no avail, I need use some real help.

I have a windows application that queries a json file via the web where I need to extract the following values and populate textboxes in my application based on a certain callsign (I am using CXA106 as an example):

textBoxDeparture.Text = "" Need to populate with "flight_plan": "departure": value for "callsign": "CXA106"
textBoxArrival.Text = "" Need to populate with "flight_plan": "arrival": value "callsign": "CXA106"
textBoxAlternate.Text = "" Need to populate with "flight_plan": "alternate": value "callsign": "CXA106"
textBoxAltitude.Text = "" Need to populate with "flight_plan": "altitude": value "callsign": "CXA106"
textBoxFlightPlan.Text = "" Need to populate with "flight_plan": "route": value "callsign": "CXA106"

Here is a sample of the json file that typically has over 1,000 pilots.

{
"general": {
"version": 3,
"reload": 1,
"update": "20210429173631",
"update_timestamp": "2021-04-29T17:36:31.7774251Z",
"connected_clients": 1087,
"unique_users": 1029
},
"pilots": [
{
"cid": 1223456,
"name": "Frank Smith",
"callsign": "ASA001",
"server": "UK-1",
"pilot_rating": 0,
"latitude": 45.59057,
"longitude": -122.5972,
"altitude": 31,
"groundspeed": 11,
"transponder": "1501",
"heading": 119,
"qnh_i_hg": 30.24,
"qnh_mb": 1024,
"flight_plan": {
"flight_rules": "I",
"aircraft": "A320/L",
"aircraft_faa": "A320/L",
"aircraft_short": "A320",
"departure": "KSAN",
"arrival": "KPDX",
"alternate": "KSEA",
"cruise_tas": "445",
"altitude": "36000",
"deptime": "1510",
"enroute_time": "0211",
"fuel_time": "0328",
"remarks": "PBN/A1B1C1D1O1S1 DOF/210429 REG/N625VA EET/KZOA0037 KZSE0120 OPR/ASA RMK/TCAS SIMBRIEF /V/",
"route": "PADRZ2 EHF J5 FMG J92 LMT GALLO TMBRS2",
"revision_id": 1
},
"logon_time": "2021-04-29T15:43:52.3955569Z",
"last_updated": "2021-04-29T17:36:31.1795763Z"
},
{
"cid": 2182955,
"name": "John Smith CYUL",
"callsign": "CXA106",
"server": "CANADA",
"pilot_rating": 0,
"latitude": 3.89123,
"longitude": 82.7544,
"altitude": 39879,
"groundspeed": 503,
"transponder": "2200",
"heading": 318,
"qnh_i_hg": 29.8,
"qnh_mb": 1009,
"flight_plan": {
"flight_rules": "I",
"aircraft": "H/B78X/L",
"aircraft_faa": "H/B78X/L",
"aircraft_short": "B78X",
"departure": "YPPH",
"arrival": "VIDP",
"alternate": "OPST",
"cruise_tas": "499",
"altitude": "34000",
"deptime": "1130",
"enroute_time": "0933",
"fuel_time": "1141",
"remarks": "PBN/A1B1C1D1L1O1S2 DOF/210429 REG/CCXCB EET/VCCF0518 VOMF0704 VABF0813 VIDF0854 SEL/CXCB OPR/CXA PER/D RALT/WIII VCBI RMK/TCAS SIMBRIEF /T/",
"route": "KEELS T12 MERIB M641 IKASA/N0500F360 M641 RUXER/N0495F380 M641 KAT/N0498F370 A465 MMV/N0495F380 Q24 BAVOX BAVOX5A",
"revision_id": 0
},
"logon_time": "2021-04-29T15:43:52.396407Z",
"last_updated": "2021-04-29T17:36:28.4532693Z"
},
{
"cid": 1205454,
"name": "Bill Miller CYOW",
"callsign": "SIA2015",
"server": "USA-EAST",
"pilot_rating": 1,
"latitude": 43.4906,
"longitude": 132.10117,
"altitude": 8248,
"groundspeed": 236,
"transponder": "2200",
"heading": 87,
"qnh_i_hg": 29.71,
"qnh_mb": 1006,
"flight_plan": {
"flight_rules": "I",
"aircraft": "H/B744/L",
"aircraft_faa": "H/B744/L",
"aircraft_short": "B744",
"departure": "UHWW",
"arrival": "RJAA",
"alternate": "RJGG",
"cruise_tas": "490",
"altitude": "35000",
"deptime": "0000",
"enroute_time": "0000",
"fuel_time": "0000",
"remarks": "PBN/A1B1D1O1S2 DOF/210429 REG/N487SB EET/RJJJ0033 OPR/SIA PER/D RMK/TCAS /V/",
"route": "PERAS5 PERAS A723 ARLAS B451 IGROD Y304 GUGBI Y30 SWAMP SWAMPT",
"revision_id": 1
},
"logon_time": "2021-04-29T15:43:52.4699149Z",
"last_updated": "2021-04-29T17:36:31.2559913Z"
},
],
"facilities": [
{
"id": 0,
"short": "OBS",
"long": "Observer"
},
{
"id": 1,
"short": "FSS",
"long": "Flight Service Station"
},
{
"id": 2,
"short": "DEL",
"long": "Clearance Delivery"
},
{
"id": 3,
"short": "GND",
"long": "Ground"
},
{
"id": 4,
"short": "TWR",
"long": "Tower"
},
{
"id": 5,
"short": "APP",
"long": "Approach/Departure"
},
{
"id": 6,
"short": "CTR",
"long": "Enroute"
}
],
"ratings": [
{
"id": -1,
"short": "INAC",
"long": "Inactive"
},
{
"id": 0,
"short": "SUS",
"long": "Suspended"
},
{
"id": 1,
"short": "OBS",
"long": "Observer"
},
{
"id": 2,
"short": "S1",
"long": "Tower Trainee"
},
{
"id": 3,
"short": "S2",
"long": "Tower Controller"
},
{
"id": 4,
"short": "S3",
"long": "Senior Student"
},
{
"id": 5,
"short": "C1",
"long": "Enroute Controller"
},
{
"id": 6,
"short": "C2",
"long": "Controller 2 (not in use)"
},
{
"id": 7,
"short": "C3",
"long": "Senior Controller"
},
{
"id": 8,
"short": "I1",
"long": "Instructor"
},
{
"id": 9,
"short": "I2",
"long": "Instructor 2 (not in use)"
},
{
"id": 10,
"short": "I3",
"long": "Senior Instructor"
},
{
"id": 11,
"short": "SUP",
"long": "Supervisor"
},
{
"id": 12,
"short": "ADM",
"long": "Administrator"
}
],
"pilot_ratings": [
{
"id": 0,
"short_name": "NEW",
"long_name": "Basic Member"
},
{
"id": 1,
"short_name": "PPL",
"long_name": "Private Pilot Licence"
},
{
"id": 3,
"short_name": "IR",
"long_name": "Instrument Rating"
},
{
"id": 7,
"short_name": "CMEL",
"long_name": "Commercial Multi-Engine License"
},
{
"id": 15,
"short_name": "ATPL",
"long_name": "Airline Transport Pilot License"
}
]
}

I have been able to extract all the json values for a CXA106, but for the life of me, I cannot figure out how to populate the textboxes.

Here is my test code:

 using System;
 using System.Data;
 using System.Linq;
 using System.Net; 
 using System.IO; 
 using System.Windows.Forms;
 using Newtonsoft.Json; 
 using Newtonsoft.Json.Linq; 
    
 namespace JSONTest
 {
     public partial class Form1 : Form
     {
         public Form1()
         {
             InitializeComponent();
         }
    
         string stringServers = "https://URLTODATASERVER"; //Variable to data server.
    
         private void ButtonImportFP_Click(object sender, EventArgs e)
         {
             //Clear previous flight plan.
             textBoxDeparture.Text = "";
             textBoxArrival.Text = "";
             textBoxAlternate.Text = "";
             textBoxAltitude.Text = "";
             textBoxFlightPlan.Text = "";
    
             //Create a request for the data server.
             WebRequest webrequestDataServer = WebRequest.Create(stringServers);
    
             //Get the response.
             WebResponse webresponseDataServer = webrequestDataServer.GetResponse();
    
             //Get the stream containing flight data returned by the data server.
             Stream streamDataServer = webresponseDataServer.GetResponseStream();
    
             //Open the stream using a StreamReader
             StreamReader streamreaderDataServer = new StreamReader(streamDataServer);
    
             //Loop thru the file
             while (!streamreaderDataServer.EndOfStream)
             {
                 //Read the flight data.
                 string stringDataServer = streamreaderDataServer.ReadLine();
    
                 //Search for pilot call-sign.
                 string stringCallSign = "CXA106";
    
                 JObject jasonObject = JObject.Parse(stringDataServer);
    
                 JObject jsonObjectDataServer = jasonObject["pilots"].Values<JObject>()
                     .Where(m => m["callsign"].Value<string>() == stringCallSign)
                     .FirstOrDefault();
    
                 //If flight plan exists.
                 if (jsonObjectDataServer != null)
                 {
                     //Populate textboxes with flight plan.
                     foreach (JProperty jsonProperty in jsonObjectDataServer.Properties())
                     {
                         textBoxDeparture.Text = "" //Need to populate with "flight_plan": "departure": value for "callsign": "CXA106"
             textBoxArrival.Text = "" //Need to populate with "flight_plan": "arrival": value "callsign": "CXA106"
             textBoxAlternate.Text = "" //Need to populate with "flight_plan": "alternate": value "callsign": "CXA106"
             textBoxAltitude.Text = "" //Need to populate with "flight_plan": "altitude": value "callsign": "CXA106"
                         textBoxFlightPlan.Text = "" //Need to populate with "flight_plan": "route": value "callsign": "CXA106"
                     }
                 }
                 else
                 {
                     //Flight plan not found.
                     textBoxFlightPlan.Text = "match not found";
                 }
             }
    
             //Close connections.
             streamDataServer.Close();
             streamreaderDataServer.Close();
    
         }
    
     }
 }

Your assistance would be greatly appreciated!


dotnet-csharp
· 2
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

@marcwheeler
Tips: Visual Studio can generate the required classes according to your Json structure.
Just copy Json, then open Visual Studio and select Edit => Paste Special => Paste Json As Classes.

0 Votes 0 ·

There is a caveat, in this case there are several properties that use C# keywords so without aliasing them no data will be return e.g. short is _short and long is _long, they need attention as in my code sample.

0 Votes 0 ·
karenpayneoregon avatar image
0 Votes"
karenpayneoregon answered TimonYang-MSFT commented

If you are still struggling here is the solution.

93538-pilots.png



pilots.png (8.7 KiB)
· 2
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Sorry for the delay in responding.

I managed to get everything working using a local data.json file as per your example.

I am now trying to get my application to retrieve the data from an URL and I am having issues with the public static TModel ReadJsonFromWeb<TModel>() , so further research will be required, but I am getting close. :)

0 Votes 0 ·

@marcwheeler

I am having issues with the public static TModel ReadJsonFromWeb<TModel>()

What kind of issue are you facing now? Could you please show some details?

0 Votes 0 ·
karenpayneoregon avatar image
0 Votes"
karenpayneoregon answered

Target what you need, lose the rest.

93021-figure1.png



figure1.png (136.0 KiB)
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

karenpayneoregon avatar image
0 Votes"
karenpayneoregon answered marcwheeler commented

In regards to so much code, it's not really that much e.g.

 Data data = JsonHelpers.ReadJsonFromFile<Data>("data.json");
    
 var callSign = "CXA106";
 Pilot pilot = data.pilots.FirstOrDefault(pilotInstance => pilotInstance.callsign == callSign);
    
 if (pilot is not null)
 {
     Console.WriteLine($"Pilot: {pilot.Name}");
        
     Console.WriteLine("Flight plan details");
     var flightPlan = pilot.flight_plan;
     Console.WriteLine($"   Arrival: {flightPlan.arrival}");
     Console.WriteLine($"  Aircraft: {flightPlan.aircraft}");
     Console.WriteLine($"  Altitude: {flightPlan.altitude}");
     Console.WriteLine($"     Route: {flightPlan.route}");
 }
 else
 {
     Console.WriteLine("No match");
 }

Just adapt the console write lines to assign values to TextBox controls.
92954-figure1.png


92928-kpmvp.png



figure1.png (19.9 KiB)
kpmvp.png (2.0 KiB)
· 3
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Because I only need the data from Flight_Plan, does that mean I only need to create the public class Flight_Plan?

That would certainly eliminate a lot of code.

0 Votes 0 ·

You are receiving a Json response from a Web service.

HttpClient() is the preferred way to get the response back from a Http request.

https://www.infoworld.com/article/3198673/when-to-use-webclient-vs-httpclient-vs-httpwebrequest.html

You got too much code on a simple Json response from a HTTP request.

0 Votes 0 ·

does that mean I only need to create the public class Flight_Plan?

Well this is part of coding, to comprehend your code so why not jump in and see what happens then next time from understanding this time you can theorize or know what to expect.

A classic example of not learning is to rely on others entirely rather than jump in. One is not always successful the first or 10th time but when they do they are smarter.

0 Votes 0 ·
karenpayneoregon avatar image
0 Votes"
karenpayneoregon answered marcwheeler commented

Hello,

You need to have classes which represent your JSON data e.g.

 public class Data
 {
     public General general { get; set; }
     public Pilot[] pilots { get; set; }
     public Facility[] facilities { get; set; }
     public Rating[] ratings { get; set; }
     public Pilot_Ratings[] pilot_ratings { get; set; }
 }
    
 public class General
 {
     public int version { get; set; }
     public int reload { get; set; }
     public string update { get; set; }
     public DateTime update_timestamp { get; set; }
     public int connected_clients { get; set; }
     public int unique_users { get; set; }
 }
    
 public class Pilot
 {
     public int cid { get; set; }
     [JsonProperty("name")]
     public string Name { get; set; }
     public string callsign { get; set; }
     public string server { get; set; }
     public int pilot_rating { get; set; }
     public float latitude { get; set; }
     public float longitude { get; set; }
     public int altitude { get; set; }
     public int groundspeed { get; set; }
     public string transponder { get; set; }
     public int heading { get; set; }
     public float qnh_i_hg { get; set; }
     public int qnh_mb { get; set; }
     public Flight_Plan flight_plan { get; set; }
     public DateTime logon_time { get; set; }
     public DateTime last_updated { get; set; }
    
     public override string ToString() => Name;
    
 }
    
 public class Flight_Plan
 {
     public string flight_rules { get; set; }
     public string aircraft { get; set; }
     public string aircraft_faa { get; set; }
     public string aircraft_short { get; set; }
     public string departure { get; set; }
     public string arrival { get; set; }
     public string alternate { get; set; }
     public string cruise_tas { get; set; }
     public string altitude { get; set; }
     public string deptime { get; set; }
     public string enroute_time { get; set; }
     public string fuel_time { get; set; }
     public string remarks { get; set; }
     public string route { get; set; }
     public int revision_id { get; set; }
 }
    
 public class Facility
 {
     public int id { get; set; }
     public string _short { get; set; }
     public string _long { get; set; }
 }
    
 public class Rating
 {
     public int id { get; set; }
     [JsonProperty("_short")]
     public string ShortValue { get; set; }
     public string _long { get; set; }
 }
    
 public class Pilot_Ratings
 {
     public int id { get; set; }
     public string short_name { get; set; }
     public string long_name { get; set; }
 }

Then have a method to deserialize (there is an empty method below for you to implement). For me to provide a simple code sample I read from a file.

 public class JsonHelpers
 {
     public static TModel ReadJsonFromFile<TModel>(string fileName)
     {
         var model = default(TModel);
    
         if (!File.Exists(fileName)) return model;
            
         var json = File.ReadAllText(fileName);
         model = JsonConvert.DeserializeObject<TModel>(json);
    
         return model;
    
     }
    
     public static TModel ReadJsonFromWeb<TModel>()
     {
         throw new NotImplementedException();
     }
 }


Simple test in a console project.

 Data data = JsonHelpers.ReadJsonFromFile<Data>("data.json");
    
 foreach (var dataPilot in data.pilots)
 {
     Console.WriteLine(
         $"{dataPilot.Name,-20}Air craft: {dataPilot.flight_plan.aircraft, -10} call-sign {dataPilot.callsign,-10}");
 }


Windows form project you would use a BindingSource to provide navigation then data bind to TextBox control e.g. SomeText.DataBinding.Add("Text", someBindingSource,"SomePropertyName"); and finally a BindingNavigator for moving between records.

One final thing, if there is a plan to update/save look at implementing INotifyPropertyChanged Interface, simple example

 public class Contacts : INotifyPropertyChanged
 {
     private string _firstName;
     private string _lastName;
     private int? _contactTypeIdentifier;
    
     public int Id => ContactId;
     public int ContactId { get; set; }
    
     public string FirstName
     {
         get => _firstName;
         set
         {
             _firstName = value;
             OnPropertyChanged();
         }
     }
     public string LastName
     {
         get => _lastName;
         set
         {
             _lastName = value;
             OnPropertyChanged();
         }
     }
    
     public int? ContactTypeIdentifier
     {
         get => _contactTypeIdentifier;
         set
         {
             _contactTypeIdentifier = value;
             OnPropertyChanged();
         }
     }
    
    
     public event PropertyChangedEventHandler PropertyChanged;
     protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
     {
         PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
     }
    
 }

Edit

I noticed facilities model had C# reserve words so the above definition must be aliased for short and long properties.

 public class facility
 {
     public int id { get; set; }
     [JsonProperty("short")]
     public string Short { get; set; }
     [JsonProperty("long")]
     public string Long { get; set; }
 }


92703-kpmvp.png



kpmvp.png (2.0 KiB)
· 1
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Hi all,

I did not think that so much code would be required to simply populate 5 textboxes:
textBoxDeparture.Text = "" Need to populate with "flight_plan": "departure": value for "callsign": "CXA106"
textBoxArrival.Text = "" Need to populate with "flight_plan": "arrival": value "callsign": "CXA106"
textBoxAlternate.Text = "" Need to populate with "flight_plan": "alternate": value "callsign": "CXA106"
textBoxAltitude.Text = "" Need to populate with "flight_plan": "altitude": value "callsign": "CXA106"
textBoxFlightPlan.Text = "" Need to populate with "flight_plan": "route": value "callsign": "CXA106"

It looks like have some reading and testing to do. :)


0 Votes 0 ·
DuaneArnold-0443 avatar image
1 Vote"
DuaneArnold-0443 answered

You take a complete set of what constitutes the Json array, and I am not talking about 1,000 items in the Json array, but what constitutes an object in the array along with the Json array itself.

https://www.c-sharpcorner.com/UploadFile/pranayamr/generate-class-from-json-xml-in-visual-studio/

You generate the class from the Json.

You can use Newtonsoft.Json to deserialize the Json response into the custom class/object that you created.

You can look at the Github solution example looking at the ServiceLayer classes in the folder that make calls to a Web service that sends back a Json response and how it deseralizes the Json response into a custom class/object, a class name prefixed with dto. There are methods like Find() that works with a single json object being created returned by the Json response, and there is a GetAll() that takes a response of a Json array, deseralizes each json object in the array and loads the custom object into a List<T>.

The Entities project holds the DTO(s).

https://github.com/darnold924/PubCompanyCore3.x

It's just another way of doing it by accessing the properties of the custom class/object.

HTH

5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.