Fiddler access nested json to modify - c#

i somehow can´t reach the objects in a nested json. I easily can reach the element test, but how to reach this_month inside "stats"? this is my json:
{"test":"OK","stats":{"this_month":"1653","this_week":"1653"}}
this is my code inside the customrules.cs
var oResponseBody = oSession.GetResponseBodyAsString();
JSON.JSONParseResult oJSON = JSON.JsonDecode(oResponseBody) as JSON.JSONParseResult;
Hashtable oObj = oJSON.JSONObject as Hashtable;
oObj["test"] = "changed";
var modBytes = Fiddler.WebFormats.JSON.JsonEncode(oObj);
// Convert json to bytes, storing the bytes in request body
var mod = System.Text.Encoding.UTF8.GetBytes(modBytes);
oSession.ResponseBody = mod;
As soon as I want to acces this_month in "stats" with this: oObj["stats"]["this_month"] = "changed"; my fiddler get´s errors and crashes.

Related

Custom string from TextBox in webrequest

i am trying to send a HttpWebRequest with the following body :
string body = "{\"prompt\": \"MyText\",\"n\": 2,\"size\": \"256x256\",\"response_format\":\"b64_json\"}";
the request works perfectly with this body, but everytime i try to change "MyText" with a text from textbox, i get an error 400 from server.
i tried this (return error 400):
string body = "{\"prompt\":" +textBox1.Text+",\"n\": 2,\"size\": \"256x256\",\"response_format\":\"b64_json\"}";
any ideas ?
It is not recommended to build your JSON manually as you will highly expose to syntax errors due to missing/extra quotes, braces, etc especially when dealing with complex objects/arrays.
Using the libraries such as System.Text.Json or Newtonsoft.Json for the JSON serialization. This is safer and easier compared to building it manually.
using System.Text.Json;
var obj = new
{
prompt = textBox1.Text,
n = 2,
size = "256x256",
response_format = "b64_json"
};
string body = JsonSerializer.Serialize(obj);
using Newtonsoft.Json;
string body = JsonConvert.SerializeObject(obj);

Accessed JArray values with invalid key value in different json

I've this json:
{
"status": true,
"Text": "Example"
}
But sometimes this could change, so I need to check if the index Text is available in the response passed, code:
var container = (JContainer)JsonConvert.DeserializeObject(response);
var message = container["Text"];
the problem is that I get this exception on message (if the json doesn't contain the key text):
{"Accessed JArray values with invalid key value: \"Text\". Int32 array index expected."}
How can I avoid this problem?
What version of NewtonSoft are you using?
The following results in message being null and no exception is thrown.
var res = #"{""status"": true }";
var container = (JContainer)JsonConvert.DeserializeObject(res);
var message = container["Text"];
// message = null
Update:
Following your response, even this doesn't throw the exception you're seeing:
var res = #"{}";
var container = (JContainer)JsonConvert.DeserializeObject(res);
var message = container["Text"];
Having updated my code to reflect yours with the same version I'm still not getting the exception you're seeing. This is what I'm doing:
var res = #"{""trace"":{""details"":{""[date]"":""[29-02-2016 17:07:29.773750]"",""[level]"":""[info]"",""[message]"":""[System Done.]""},""context"":[[{""ID"":""John Dillinger""}]]}}";
var container = (JContainer)JsonConvert.DeserializeObject(res);
var message = container["Text"];
The message variable is still null.
In light of this perhaps try create a simple console application with the above code and see if you get the same exception?

Parsing a generic variable from a Json text

I'm trying to parse the info from a json object obtained via api, but in this request, I'm trying to get just one variable. I just want to get the summonerLevel variable.
{
"test": {
"id":107537,
"name":"test",
"profileIconId":785,
"summonerLevel":30,
"revisionDate":1440089189000
}
}
I've been trying to it with this code and I know that if I write
p.summonerLevel = (int)(obj.test.summonerLevel)
it will work, but the problem is that test is not a static name, and it will be changing within each request I do. Any good example on how to do it?
Thanks
WebClient c = new WebClient();
string data = c.DownloadString("https://las.api.pvp.net/api/lol/las/v1.4/summoner/by-name/"+summonerName+"?api_key=<api-key>");
dynamic obj = JsonConvert.DeserializeObject(data);
p.summonerLevel = (int)(obj.tempName.summonerLevel);
Something like this?
int summonerLevel= (int)JObject.Parse(data).First.First["summonerLevel"];

C# Extracting data from Json or DataSets - Porting from Python (Json to Dict)

I have the following Python script which I need to port to C#. This gets a JSON response from a URL and then pops it into a dictionary. Then it checks for the data next_page and if there is data (it's not empty) it then returns true. Underneath I'll paste the C# code I have but I'm really struggling to do the final part. I don't know and I certainly don't want to understand the data in the JSON response, I just want to know if the field next_page is there.
# Gets JSON response
response = requests.get(url, auth=(user, pwd))
if response.status_code != 200:
print('Status:', response.status_code, 'Problem with the request. Exiting.')
exit()
data = response.json()
if(data['next_page']):
return True
else:
return False
So this is the c# code I've got:
using Newtonsoft.Json;
string response = "";
using (WebClient client = new WebClient())
{
client.UseDefaultCredentials = true;
client.Credentials = new NetworkCredential(user, password);
try
{
response = client.DownloadString(url);
} catch (Exception e)
{
throw e;
}
}
XmlDocument xml = JsonConvert.DeserializeXmlNode(json, "RootObject");
XmlReader xr = new XmlNodeReader(xml);
DataSet ds = new DataSet("Json Data");
ds.ReadXml(xr);
From what I've seen on the web DataSets work best when you know what the data inside of it is. I just want to know if there is a field called next_page and if there is, is it empty or does it have data. I'm just struggling to get anything out of the DataSet.
You will want to include the JSON.net nuget package (http://james.newtonking.com/json) this lets you deserialize the JSON response into a dictionary (or preferably a new class) allowing you to access the response.
eg add this into your try catch after including the library
var dict = Newtonsoft.Json.JsonConvert.DeserializeObject<Dictionary<string, string>>(response);
Alternativly you could create a new class that represents the expected JSON and deserialize into that
public class ResponseObject
{
public string next_page { get; set; }
}
var responseResult = Newtonsoft.Json.JsonConvert.DeserializeObject<ResponseObject>(response);

How to get Coordinates when Address is Known?

I derived/adapted the following code from Adam Freeman's book "Metro Revealed: Building Windows 8 apps with XAML and C#" to get the Address when the Coordinates are known:
public static async Task<string> GetAddressForCoordinates(double latitude, double longitude)
{
HttpClient httpClient = new HttpClient {BaseAddress = new Uri("http://nominatim.openstreetmap.org")};
HttpResponseMessage httpResult = await httpClient.GetAsync(
String.Format("reverse?format=json&lat={0}&lon={1}", latitude, longitude));
JsonObject jsonObject = JsonObject.Parse(await httpResult.Content.ReadAsStringAsync());
return jsonObject.GetNamedObject("address").GetNamedString("road");
}
How can I get the opposite (the Coordinates if the Address is known)?
UPDATE
I'm adding a bounty to this; what I've got already (shown above) is the reverse geocoding (getting the address for the coordinates); what I need is geocoding (getting the coordinates for the address).
Based on my reverse geocoding code above, I'm guessing it might be something like this:
public static async Task<string> GetCoordinatesForAddress(string address)
{
HttpClient httpClient = new HttpClient {BaseAddress = new Uri("http://nominatim.openstreetmap.org")};
HttpResponseMessage httpResult = await httpClient.GetAsync(
String.Format("format=json&address={0}", address));
JsonObject jsonObject = JsonObject.Parse(await httpResult.Content.ReadAsStringAsync());
return jsonObject.GetNamedObject("address").GetNamedString("lat"); // <-- what about "lon"?
}
...but I don't know how to combine the two coordinate (longitude and latitude) values (assuming this is correct, or close to being correct). Can anybody verify this, clean it up, or provide a better example (either using nominatim or otherwise)?
UPDATE 2
To answer Peter Ritchie's question/comment below:
In the original (reverse geocoding code), I've got:
return jsonObject.GetNamedObject("address").GetNamedString("road");
It simply returns the road; so something like "157 Riverside Avenue" I assume.
But for geocoding (needing two values, a longitude and a latitude), I've got this pseudocode:
return jsonObject.GetNamedObject("address").GetNamedString("lat"); // <-- what about "lon"?
So I don't know if I need to change the return value from Task<string> to Task<List and call (verbose pseudocode) [Note: I'm having a hard time escaping the angle brackets for Task with a List of string]:
var latitude jsonObject.GetNamedObject("address").GetNamedString("lat");
var longitude jsonObject.GetNamedObject("address").GetNamedString("lat");
List<string> listCoordinates = new List<string>();
listCoordinates.Add(latitude);
listCoordinates.Add(longitude);
return listCoordinates;
...or like so:
string latitude jsonObject.GetNamedObject("address").GetNamedString("lat");
string longtude jsonObject.GetNamedObject("address").GetNamedString("long");
return string.Format("{0};{1}", latitude, longitude);
...or ???
UPDATE 3
In response to the proffered Json code for geocoding:
Based on the original reverse geocode code, shouldn't the call be more like this:
HttpClient httpClient = new HttpClient { BaseAddress = new Uri("http://nominatim.openstreetmap.org/") };
var httpResult = await httpClient.GetAsync(
String.Format("search?format=json&addressdetails={0}", address);
...but at any rate:
The JArray type is not recognized, though JsonArray is.
The JValue type is not recognized, though JsonValue is.
The JsonConverter type is not recognized; perhaps part of Json.Net?
The closest I can come to getting the proferred code to compile is:
var result = await httpResult.Content.ReadAsStringAsync();
var r = (JsonArray)JsonConverter.DeserializeObject(result);//<-- JsonConvert[er] not recognized; part of Json.NET?
var latString = ((JsonValue)r[0]["lat"]).ValueType as string;
var longString = ((JsonValue)r[0]["lon"]).ValueType as string;
...but even with this (close but no Bob Seger), JsonConvert as well as JsonConverter are not recognized.
UPDATE 4
After slogging more concertedly through the documentation at http://wiki.openstreetmap.org/wiki/Nominatim#Search, I think my original (reverse geocode) method might be better as:
public static async Task`<string`> GetAddressForCoordinates(double latitude, double longitude)
{
HttpClient httpClient = new HttpClient {BaseAddress = new Uri("http://nominatim.openstreetmap.org/")};
HttpResponseMessage httpResult = await httpClient.GetAsync(
String.Format("reverse?format=json&lat={0}&lon={1}", latitude, longitude));
JsonObject jsonObject = JsonObject.Parse(await httpResult.Content.ReadAsStringAsync());
string house = jsonObject.GetNamedObject("addressparts").GetNamedString("house");
string road = jsonObject.GetNamedObject("addressparts").GetNamedString("road");
string city = jsonObject.GetNamedObject("addressparts").GetNamedString("city");
string state = jsonObject.GetNamedObject("addressparts").GetNamedString("state");
string postcode = jsonObject.GetNamedObject("addressparts").GetNamedString("postcode");
string country = jsonObject.GetNamedObject("addressparts").GetNamedString("country");
return string.Format("{0} {1}, {2}, {3} {4} ({5})", house, road, city, state, postcode, country);
}
This would return, for the corresponding coordinate args passed in, something like: "157 Riverside Avenue, Champaign, IL 55555 (USA)"
What I find odd about the documentation is there is no "state" element among the address parts; if that is really true, and not just a documentation oversight, my code above would fail on the call to GetNamedString("state").
I'm still not sure what the right syntax, etc., should be for the opposite (geocode) method, getting coordinates back after passing in an address.
UPDATE 5
Okay, I downloaded Json.NET and got it compiling. I haven't tested yet, but I've marked Peter Ritchie's as THE (50-point) answer.
This is the code I'm using:
public static async Task<string> GetCoordinatesForAddress(string address)
{
HttpClient httpClient = new HttpClient { BaseAddress = new Uri("http://nominatim.openstreetmap.org/") };
HttpResponseMessage httpResult = await httpClient.GetAsync(
String.Format("search?q={0}&format=json&addressdetails=1", Pluggify(address))); // In my Pluggify() method, I replace spaces with + and then lowercase it all
var result = await httpResult.Content.ReadAsStringAsync();
var r = (JArray)JsonConvert.DeserializeObject(result);
var latString = ((JValue)r[0]["lat"]).Value as string;
var longString = ((JValue)r[0]["lon"]).Value as string;
return string.Format("{0};{1}", latString, longString);
}
Also:
A funny thing happened on the way back to this forum: while installing Json.NET via NuGet, I also saw ".NET's fastest JSON Serializer by ServiceStack" which claims to be 3X faster than Json.NET. FIWW, it has been updated more recently than Json.NET. Thoughts/reaction?
UPDATE 6
I have this code to implement this (app id and code have been changed to protect the semi-innocent
(me)):
// If address has not been explicitly entered, try to suss it out:
address = textBoxAddress1.Text.Trim();
lat = textBoxLatitude1.Text.Trim();
lng = textBoxLongitude1.Text.Trim();
if (string.IsNullOrWhiteSpace(address))
{
address = await SOs_Classes.SOs_Utils.GetAddressForCoordinates(lat, lng);
}
. . .
public async static Task<string> GetAddressForCoordinates(string latitude, string longitude)
{
string currentgeoLoc = string.Format("{0},{1}", latitude, longitude);
string queryString = string.Empty;
string nokiaAppID = "j;dsfj;fasdkdf";
object nokiaAppCode = "-14-14-1-7-47-178-78-4";
var hereNetUrl = string.Format(
"http://demo.places.nlp.nokia.com/places/v1/discover/search?at={0}&q={1}&app_id={2}
&app_code={3}&accept=application/json",
currentgeoLoc, queryString, nokiaAppID, nokiaAppCode);
// get data from HERE.net REST API
var httpClient = new HttpClient();
var hereNetResponse = await httpClient.GetStringAsync(hereNetUrl);
// deseralize JSON from Here.net
using (var tr = new StringReader(hereNetResponse))
using (var jr = new JsonTextReader(tr))
{
var rootObjectResponse = new JsonSerializer
().Deserialize<JsonDOTNetHelperClasses.RootObject>(jr);
var firstplace = rootObjectResponse.results.items.First();
return HtmlUtilities.ConvertToText(firstplace.vicinity);
// NOTE: There is also a title (such as "Donut Shop", "Fire stations", etc.?) and type (such as "residence" or "business", etc.?)
}
}
...but on this line in GetAddressForCoordinates():
var firstplace = rootObjectResponse.results.items.First();
...I get this err msg: "*System.InvalidOperationException was unhandled by user code
HResult=-2146233079
Message=Sequence contains no elements
Source=System.Core
StackTrace:
at System.Linq.Enumerable.First[TSource](IEnumerable`1 source)
at SpaceOverlays.SOs_Classes.SOs_Utils.d__12.MoveNext() in c:...*"
The value of hereNetResponse is:
{"results":{"items":[]},"search":{"context":{"location":{"position":[38.804967,-90.113183],"address":
{"postalCode":"62048","city":"Hartford","stateCode":"IL","county":"Madison","countryCode":"USA","country":"
USA","text":"Hartford IL 62048
USA"}},"type":"urn:nlp-types:place","href":"http://demo.places.nlp.nokia.com/places/v1/places/loc-
dmVyc2lvbj0xO3RpdGxlPUhhcnRmb3JkO2xhdD0zOC44MDQ5Njc7bG9uPS05MC4xMTMxODM7Y2l0eT1IY
XJ0Zm9yZDtwb3N0YWxDb2RlPTYyMDQ4O2NvdW50cnk9VVNBO3N0YXRlQ29kZT1JTDtjb3VudHk9TWFka
XNvbjtjYXRlZ29yeUlkPWNpdHktdG93bi12aWxsYWdl;context=Zmxvdy1pZD02YmUzZDM4Yi0wNGVhLTUyM
jgtOWZmNy1kNWNkZGM0ODI5OThfMTM1NzQyMDI1NTg1M18wXzE2MA?
app_id=F6zpNc3TjnkiCLwl_Xmh&app_code=QoAM_5BaVDZvkE2jRvc0mw"}}}
...so it would appear that there is valid info inside there, such as should return "Hartford, IL"
And at any rate, a blank return value shouldn't throw an exception, I would think...
What you're asking about is simply "geocoding". If you want to use Nominatim specifically, they call this "Search". This is, to a certain extent, address validation; but part of the "validation" is including coordinates (bounding box, lat/long, etc.; depending on what is searched for and what the type of result). There's lots of details about the results, too much to simply post here; but this detail can be found here: http://wiki.openstreetmap.org/wiki/Nominatim#Search (including examles).
You'll have to parse the results (XML, JSON, or HTML) to get the fields you're interested it.
Update 1:
As to what to do with the actual values: it depends. If you want to view the coordinates in a form, you can simply put the lat and long strings into individual controls. If you want to put it in a single control, could use string.Format("{0}, {1}", latString, longString). If you want to use the coords with various methods/types for a Windows Store app, you might need to use the Microsoft.Maps.MapControl.Location class. For example:
Double latNumber;
Double longNumber;
if(false == Double.TryParse(latString, out latNumber)) throw new InvalidOperationException();
if(false == Double.TryParse(longString, out longNumber)) throw new InvalidOperationException();
var location = new Location(latNumber, longNumber);
The above assumes you've extracted the lat and long from the response and put them in latString, longString respectively.
Some interfaces may require lat/long as separate double values, in which case just use latNumber and longNumber above.
Over and above that, it really depends specifically on the interfaces you want to use. But, the above should give you enough to use most interfaces.
Update 2:
If the question isn't "how to get coordinates" but "how to parse json objects" then I'd recommend using JSon.Net to get at the lat/long strings in the json result. For example:
var httpClient = new HttpClient();
var httpResult = await httpClient.GetAsync(
"http://nominatim.openstreetmap.org/search?q=135+pilkington+avenue,+birmingham&format=json&polygon=1&addressdetails=1");
var result = await httpResult.Content.ReadAsStringAsync();
var r = (JArray) JsonConvert.DeserializeObject(result);
var latString = ((JValue) r[0]["lat"]).Value as string;
var longString = ((JValue)r[0]["lon"]).Value as string;
...see above w.r.t. what to do with latString and longString
If your looking for google maps geocoding, you can find it here:
https://developers.google.com/maps/documentation/geocoding/
and an example use is:
http://maps.googleapis.com/maps/api/geocode/json?address=1600+Amphitheatre+Parkway,+Mountain+View,+CA&sensor=false
convert to Json, and take the Geometry object.
in regards to how to, basically, return two values from a function, in C# you have 4 options:
convert both objects into a single object of the same type (in case of strings, you just separate them by a delimiter, like you did) and then parse both out afterwards.
return a list - in this case a Task (or array).
create a new class/object that contains both (in this case you can call it Geometry for instance).
return one or both of the objects by requiring them to be passed as a reference to the function. In an async function, this is bound to be very tricky, but depending on who calls the function and who processes the result, it might be possible.
Microsoft Mappoint also contaisn an API you could make use of. It is able to return geocoordinates.

Categories