C# Parsing JSON w/ Newtonsoft - c#

I'm very new to c#, so I apologize if this doesn't make any sense!
Using a C# console application, I'm having a hard time parsing a detailed json response and assigning json values to variables. I thought I had everything working by deserializing the json to a string until about 200 iterations in (I'll be geocoding over a million addresses), I received a response with an empty result array that crashed my application. Now I'm trying a new approach using JObject, JProperty, and JToken, but not having much luck.
My json example is is follows ..
{
"input": {
"address_components": {
"number": "123",
"predirectional": "E",
"street": "Main",
"suffix": "St",
"formatted_street": "E Main St",
"city": "Mesa",
"state": "AZ",
"zip": "85209",
"country": "US"
},
"formatted_address": "123 E Main St, Mesa, AZ 85209"
},
"results": [
{
"address_components": {
"number": "123",
"predirectional": "E",
"street": "Main",
"suffix": "St",
"formatted_street": "E Main Ave",
"city": "Mesa",
"county": "Maricopa County",
"state": "AZ",
"zip": "85209",
"country": "US"
},
"formatted_address": "123 E Main St, Mesa, AZ 85209",
"location": {
"lat": 33.123456,
"lng": -111.123456
},
"accuracy": 1,
"accuracy_type": "range_interpolation",
"source": "TIGER\/Line\u00ae dataset from the US Census Bureau",
"fields": {
"congressional_district": {
"name": "Congressional District 5",
"district_number": 5,
"congress_number": "114th",
"congress_years": "2015-2017"
},
"state_legislative_districts": {
"senate": {
"name": "State Senate District 16",
"district_number": "16"
},
"house": {
"name": "State House District 16",
"district_number": "16"
}
},
"school_districts": {
"unified": {
"name": "Gilbert Unified District",
"lea_code": "0403400",
"grade_low": "PK",
"grade_high": "12"
}
},
"timezone": {
"name": "MST",
"utc_offset": -7,
"observes_dst": false
}
}
},
{
"address_components": {
"number": "123",
"predirectional": "E",
"street": "Main",
"suffix": "St",
"formatted_street": "E Main St",
"city": "Mesa",
"county": "Maricopa County",
"state": "AZ",
"zip": "85209",
"country": "US"
},
"formatted_address": "123 E Main St, Mesa, AZ 85209",
"location": {
"lat": 33.123456,
"lng": -111.123456
},
"accuracy": 0.8,
"accuracy_type": "range_interpolation",
"source": "TIGER\/Line\u00ae dataset from the US Census Bureau",
"fields": {
"congressional_district": {
"name": "Congressional District 5",
"district_number": 5,
"congress_number": "114th",
"congress_years": "2015-2017"
},
"state_legislative_districts": {
"senate": {
"name": "State Senate District 16",
"district_number": "16"
},
"house": {
"name": "State House District 16",
"district_number": "16"
}
},
"school_districts": {
"unified": {
"name": "Gilbert Unified District",
"lea_code": "0403400",
"grade_low": "PK",
"grade_high": "12"
}
},
"timezone": {
"name": "MST",
"utc_offset": -7,
"observes_dst": false
}
}
}
]
}
The json that broke my original code ..
{
"input": {
"address_components": {
"number": "123",
"predirectional": "E",
"street": "Main",
"suffix": "St",
"formatted_street": "E Main St",
"city": "Mesa",
"state": "AZ",
"zip": "85209",
"country": "US"
},
"formatted_address": "123 E Main St, Mesa, AZ 85209"
},
"results": []
}
The original code ..
Uri uri = new Uri("https://api.geocod.io/v1/geocode?q=" + geocodioAddress + "&fields=cd,stateleg,school,timezone&api_key=" + app_key);
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(uri);
request.Method = WebRequestMethods.Http.Get;
request.Accept = "application/json";
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
StreamReader reader = new StreamReader(response.GetResponseStream());
string output = reader.ReadToEnd();
response.Close();
dynamic array = JsonConvert.DeserializeObject(output);
if (array.results[0] != null)
{
// cont.
}
The error msg was "Index was out of range. Must be non-negative and less than the size of the collection." The error occurs at "if (array.results[0] != null)".
Now I'm sure this isn't the best approach anyways, so I thought I'd try something new (found here: C# Parsing JSON array of objects) ..
Uri uri = new Uri("https://api.geocod.io/v1/geocode?q=" + geocodioAddress + "&fields=cd,stateleg,school,timezone&api_key=" + app_key);
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(uri);
request.Method = WebRequestMethods.Http.Get;
request.Accept = "application/json";
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
StreamReader reader = new StreamReader(response.GetResponseStream());
string json = reader.ReadToEnd();
response.Close();
var resultObjects = AllChildren(JObject.Parse(json))
.First(c => c.Type == JTokenType.Array && c.Path.Contains("results"))
.Children<JObject>();
foreach (JObject result in resultObjects)
{
foreach (JProperty property in result.Properties())
{
JToken _county = property.Value.SelectToken("county");
string county = Convert.ToString(_county);
// cont.
}
}
This looked really promising, except for three things..
I don't want to parse results[1]. You'll notice in the json response, that the second results instance has a lower accuracy score. And when I don't change the lat/lng values to hide my personal address, these two instances are different with the 2nd being much less accurate.
While I successfully got the value for the county above, I can't get a response for "formatted_address", as well as the value resets each time through the foreach loop.
In the "fields" section, there are multiple objects with the same name. For example..
JToken _county = property.Value.SelectToken("name");
How do I select which "name" I'm looking for? school district, timezone, congressional district, etc..
Again, I'm sorry for such a long post. I've been working on this all week, and just when I thought I had it figured out, one stupid address has to return no results and break everything!! I really appreciate the help of people much smarter than me ... the downside of working from home, no other brains to pick :)

If you look at the data that broke your code:
{
{
"input": {
..
},
"formatted_address": "123 E Main St, Mesa, AZ 85209"
},
"results": []
}
You have results defined as an empty array. In other words it contains zero elements. Thus trying to access the first element (at index 0) in this array results in the error that you are getting.
Instead of the test that you are doing:
if (array.results[0] != null)
{
// cont.
}
you should do:
if (array.Length != 0)
{
// cont.
}
this is because the 'results' object exists, but it is empty (length is zero).

Related

C# Add values to a JSON file without changing the initial JSON format

What I want:
To add a property in JSON file in a specific place (for this case I want to add {"name2":"Tom} after {"name":"Andrew"} ) without changing its format (empty new lines)
Current JSON
{
"Profiles": [
{
"Properties": {
"color": "blue",
"shape": "circle",
"fruit": "apple",
"name": "Andrew",
"username": "ad11",
"Password": "pass",
"country": "France",
"region": "Europe"
}
}
]
}
Current code
var json = File.ReadAllText(path);
var Jobect = JObject.Parse(json);
Jobect["Profiles"][0]["Properties"]["name2"] = "Tom";
File.WriteAllText(path, Jobect.ToString());
Resulted JSON
{
"Profiles": [
{
"Properties": {
"color": "blue",
"shape": "circle",
"fruit": "apple",
"name": "Andrew",
"username": "ad11",
"Password": "pass",
"country": "France",
"region": "Europe",
"name2": "Tom"
}
}
]
}
Desired JSON
{
"Profiles": [
{
"Properties": {
"color": "blue",
"shape": "circle",
"fruit": "apple",
"name": "Andrew",
"name2": "Tom,
"username": "ad11",
"Password": "pass",
"country": "France",
"region": "Europe"
}
}
]
}
In conclusion. How can I add a property in JSON file in a specific place and without change its format?

Can not show API response message in C# Code

I am going to generate Eway Bill API from below Request.The response of below request is showing fine in "Postmen" but at the same time when I execute this below request from C# Code then its shows an error message as "The remote server returned an error: (400) Bad Request.".
I would like to know how to show the postmen error message in C# Code.
URL :-
https://ewbbackend-preprodpub-http.internal.cleartax.co/gst/v0.1/taxable_entities/1c74ddd2-6383-4f4b-a7a5-007ddd08f9ea/ewaybill/GLD23985?activity_type=GENERATE_EWB
Header :-
Content-type : application/json
X-Cleartax-Auth-Token : b1f57327-96db-4829-97cf-2f3a59a3a548
taxable_entity_id : b1f57327-96db-4829-97cf-2f3a59a3a548
Body :-
{
"id": "GLD23985",
"transaction_date": "26/10/2020",
"source": "USER",
"document_number": "BQ/20/0251",
"type": "OUTWARD",
"transport_mode": "ROAD",
"dispatch_from_state": "HARYANA",
"sub_supply": "Supply",
"distance": "90",
"vehicle_number": "TN32N1049",
"document_type": "Tax Invoice",
"seller": {
"address1": "142/1,Trunk Road",
"address2": "Perumugai",
"city": "Via Vellore",
"gstin": "29AEKPV7203E1Z9",
"name": "K.H Exports India Private Limited",
"state": "HARYANA",
"zip_code": ""
},
"receiver": {
"address1": "4/74, VOC Street, Seenerkuppam Village, ",
"address2": "Poonamalle, Chennai 600 056",
"city": "",
"gstin": "33AAACR1714R1ZA",
"name": "KH EXPORTS INDIA PVT.LTD. (LGD)",
"state": "TAMIL NADU",
"zip_code": "600003"
},
"consignee": {
"city": "",
"state": "TAMIL NADU",
"zip_code": "600003"
},
"line_items": [
{
"cess_rate": "0",
"cess_val": "0",
"cgst_rate": "0",
"cgst_val": "0",
"description": "STYLE;91311 COLOUR;SVFD7 BELT & PA",
"gst_code": "4203",
"igst_rate": "28.00",
"igst_val": "16800.000000",
"item_code": "STYLE;91311 COLOUR;SVFD7 BELT & PA",
"quantity": "3.00",
"serial_number": "1",
"sgst_rate": "0",
"sgst_val": "0",
"taxable_val": "600.0000",
"unit_of_measurement": "NUMBERS"
},
{
"cess_rate": "0",
"cess_val": "0",
"cgst_rate": "0",
"cgst_val": "0",
"description": "STYLE;91307 COLOUR;ABFD2 BELT & PA",
"gst_code": "4203",
"igst_rate": "28.00",
"igst_val": "16800.000000",
"item_code": "STYLE;91307 COLOUR;ABFD2 BELT & PA",
"quantity": "3.00",
"serial_number": "2",
"sgst_rate": "0",
"sgst_val": "0",
"taxable_val": "600.0000",
"unit_of_measurement": "NUMBERS"
}
]
}
Response:-
{
"errors": {
"err_1": {
"code": "BAD_REQUEST_ATTR",
"message": "Pincode should have 6 digits.",
"error_group_code": 0,
"error_id": 0,
"severity": "ERROR"
}
},
"error_sources": {
"seller": {
"zip_code": {
"error_refs": [
"err_1"
]
}
}
}
}
C# Code:-
string DATA = JsonConvert.SerializeObject(tr, Newtonsoft.Json.Formatting.Indented);
using (var client = new WebClient())
{
client.Headers.Add("taxable_entities", ConfigurationManager.AppSettings["taxable_entities"]);
client.Headers.Add("X-Cleartax-Auth-Token", ConfigurationManager.AppSettings["auth-token"]);
client.Headers[HttpRequestHeader.ContentType] = "application/json";
string url = ConfigurationManager.AppSettings["host"] + ConfigurationManager.AppSettings["taxable_entities"] + "/ewaybill/" + TblHeader.Rows[0]["id"].ToString() + "?activity_type=GENERATE_EWB";
string res = client.UploadString(url, "PUT", DATA);
}
Hi my friend you can use this code to handle your respond and get your answer.
The previous examples return an HttpResponseMessage message from the controller action, but you can also use HttpResponseException to return an HttpError. This lets you return a strongly-typed model in the normal success case, while still returning HttpError if there is an error
public Product GetProduct(int id)
{
Product item = repository.Get(id);
if (item == null)
{
var message = string.Format("Product with id = {0} not found", id);
throw new HttpResponseException(
Request.CreateErrorResponse(HttpStatusCode.NotFound, message));
}
else
{
return item;
}
}

Json Serialisation adding string element at root

I am using netownsoft json.net to serlize an object but its adding string at the start I dont under stand why its doing this.
Newtonsoft.Json.JsonReaderException: Unexpected character encountered while parsing value: <. Path '', line 0, position 0.
public async Task<T> GetDataFromSageService<T>(string url, params string[] args)
where T : class
{
var uri = new Uri(string.Format(url, args));
var response = await _client.GetAsync(uri);
if (response.IsSuccessStatusCode)
{
var content = await response.Content.ReadAsStringAsync();
return Newtonsoft.Json.JsonConvert.DeserializeObject<T>(content);
}
return default(T);
}
I am using the following to encode my end point which is hosted in a wcf service.
public string GetWarehouses()
{
DataSet ds = new SqlDa().GetWarehouses();
ds.Tables[0].TableName = "Warehouses";
return JsonConvert.SerializeObject(ds, Formatting.Indented);
}
But the string i am getting back is as such
<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">
{
"Warehouses": [
{
"WarehouseID": 13016489,
"Name": "B",
"Description": "Belfast "
},
{
"WarehouseID": 13016647,
"Name": "B",
"Description": "B"
},
{
"WarehouseID": 13815467,
"Name": "Direct Delivery",
"Description": ""
},
{
"WarehouseID": 1008,
"Name": "PW",
"Description": "Postal Way"
},
{
"WarehouseID": 13016234,
"Name": "H",
"Description": "Hospital"
},
{
"WarehouseID": 13016238,
"Name": "MPC",
"Description": "Clinic"
},
{
"WarehouseID": 13029366,
"Name": "O",
"Description": "Outpatient"
},
{
"WarehouseID": 13815466,
"Name": "Returns",
"Description": ""
}
]
}
</string>
As You can see its enclosed it as a string for some reason and don't understand as to why. Is their a way with the data set to make sure that it gets converted into proper json.
If you don't want to modify your server code, you could use regex to extract legal json string from your response.
string content ="your context with xml"
Regex regex = new Regex("<string\\s*xmlns=\".*\">([\\s\\S]*)</string>");
Match match = regex.Match(content);
Response.Write(match.Groups[1].Value);
Newtonsoft.Json.JsonConvert.DeserializeObject(match.Groups[1].Value);

Create Graph Event with Room as location using C# and Microsoft.Graph nuget

Not sure how to do the location with a room in C# and Microsoft.Graph.
I want to create an event that would put the event in a room. I now the room’s email - Rainier#M365x947151.onmicrosoft.com . The code I am trying is as follows using Microsoft.Graph.
Microsoft.Graph.PhysicalAddress address = new Microsoft.Graph.PhysicalAddress();
Microsoft.Graph.Location loc = new Location();
loc.Address = address;
loc.DisplayName = "Rainier conf room";
loc.LocationEmailAddress = rainier;
var newEvent = new Event();
newEvent.Subject = subject + DateTime.Now.ToLongDateString();
newEvent.Location = loc;
newEvent.Attendees = attendees;
newEvent.Body = eventBody;
newEvent.Start = eventStartTime;
newEvent.End = eventEndTime;
Microsoft.Graph.Event createdEvent = null;
try
{
// graphclient is passed into this method
// var graphClient = AuthenticationHelper.GetAuthenticatedClient();
// var graphClient = devfish.Graph.AuthenticationHelper.MyGraphClient;
createdEvent = await graphClient.Me.Events.Request().AddAsync(newEvent);
The payload I am sending up SHOULD look something like this, but what it doesn’t look like is below. Outlook doesn’t treat it as a “room”. Thanks…
PAYLOAD WE WANT - note the odatatype and microsoft.graph.physicaladdress ...
{
"subject": "Test meeting",
"body": {
"contentType": "HTML",
"content": "Does this work (note the dates are in the past)?"
},
"start": {
"dateTime": "2017-12-01T12:00:00",
"timeZone": "Pacific Standard Time"
},
"end": {
"dateTime": "2017-12-01T14:00:00",
"timeZone": "Pacific Standard Time"
},
"location":{
"address": {"#odata.type": "microsoft.graph.physicalAddress"},
"displayName": "Rainier conf room"
},
"attendees": [
{
"emailAddress": {
"address":"joseph.healy#microsoft.com",
"name": "Joe"
},
"type": "required"
},
{
"emailAddress": {
"address":"Rainier#M365x947151.onmicrosoft.com",
"name": "Rainier"
},
"type": "Resource"
}
]
}
But instead up payload looks like this when created with C# graph.
{
"subject": "23: 42:39: BASKETBALL IS OUR SUBJECT FOR TODAYTuesday, January 9, 2018",
"body": {
"contentType": "text",
"content": "Status updates, blocking issues, and next steps"
},
"start": {
"dateTime": "2017-12-01T19:30:00.0000000",
"timeZone": "UTC"
},
"end": {
"dateTime": "2017-12-01T20:00:00.0000000",
"timeZone": "UTC"
},
"location": {
"displayName": "Rainier conf room",
"locationEmailAddress": "Rainier#M365x947151.onmicrosoft.com",
"address": {}
},
"attendees": [
{
"type": "required",
"emailAddress": {
"address": "alexw#m365x947151.onmicrosoft.com"
}
},
{
"type": "required",
"emailAddress": {
"address": "maria#fabrikam.com"
}
},
{
"type": "resource",
"emailAddress": {
"address": "Rainier#M365x947151.onmicrosoft.com"
}
}
]
}
Thanks for any help.
To get the payload you want, you'll need to:
Remove loc.LocationEmailAddress = rainier;
Add the key-value "#odata.type", "microsoft.graph.physicalAddress" to
location.AdditionalData. We had someone else recently ask for
automatic #odata.type generation so this is an additional data point
for that.
Add the name property to the room emailAddress object.

C# Cannot access child value on Newtonsoft.Json.Linq.JProperty

I was hoping you guys may be able to assist in helping me out. I would like to pull every ID within the JSON file however I am getting the following exception error:
Cannot access child value on Newtonsoft.Json.Linq.JProperty.
private void button1_Click(object sender, EventArgs e)
{
string address = "https://api.mysportsfeeds.com/v1.1/pull/nba/2016-2017-regular/cumulative_player_stats.json?team=85";
var w = new WebClient();
w.UseDefaultCredentials = true;
w.Credentials = new NetworkCredential("****", "****");
var result = w.DownloadString(address);
var obj = JObject.Parse(result);
var play = "";
foreach (JProperty child in obj["cumulativeplayerstats"])
{
play = child["player"]["ID"].ToString();
string latlong = Convert.ToString(play);
Console.WriteLine("player=" + Convert.ToString(play));
Console.ReadKey();
}
}
Here is a snippet of what the json looks like:
{
"cumulativeplayerstats": {
"lastUpdatedOn": "2017-09-11 4:45:30 PM",
"playerstatsentry": [
{
"player": {
"ID": "10138",
"LastName": "Abrines",
"FirstName": "Alex",
"JerseyNumber": "8",
"Position": "F"
},
"team": {
"ID": "96",
"City": "Oklahoma City",
"Name": "Thunder",
"Abbreviation": "OKL"
},
"stats": {
"GamesPlayed": {
"#abbreviation": "GP",
"#text": "68"
},
"Fg2PtAtt": {
"#category": "Field Goals",
"#abbreviation": "2PA",
"#text": "94"
},
"Fg2PtMade": {
"#category": "Field Goals",
"#abbreviation": "2PM",
"#text": "40"
},
"Fg3PtAtt": {
"#category": "Field Goals",
"#abbreviation": "3PA",
"#text": "247"
},
"Fg3PtMade": {
"#category": "Field Goals",
"#abbreviation": "3PM",
"#text": "94"
},
"FtAtt": {
"#category": "Free Throws",
"#abbreviation": "FTA",
"#text": "49"
},
"FtMade": {
"#category": "Free Throws",
"#abbreviation": "FTM",
"#text": "44"
}
}
},
I tried digging around on here but I cant seem to find a solution that works. If you guys can lend some of your sage wisdom, I would greatly appreciate it!
Thanks Folks!
You can modify your foreach to iterate through the playerstatsentry array:
foreach (JObject child in obj["cumulativeplayerstats"]["playerstatsentry"].OfType<JObject>())
Or without the OfType<T>:
foreach (var child in obj["cumulativeplayerstats"]["playerstatsentry"])
Taking your JSON as an example, if you are trying to locate all the properties named "ID", provided they are at same level of the hierarchy, you can utilize the "SelectTokens" method using path and wildcards to reach to your property level. This will probably save a few lines of code and is a better way to locate.
.net Fiddle for this solution - https://dotnetfiddle.net/fQ9xeH
foreach (var tokn in obj.SelectTokens("cumulativeplayerstats.playerstatsentry[*].*.ID"))
{
Console.WriteLine(tokn);
}

Categories

Resources