How to get Object values which have multiple rows in it - c#

I am converting a JSON string into a object and this object contains multiple records of a table like a row structure. each row contains some set values. It's like an object within an object. I am trying to read the value of these objects but I am unsuccessful.
WebResponse response = request.GetResponse();
Stream responseStream = response.GetResponseStream();
// Open the stream using a StreamReader for easy access.
StreamReader reader = new StreamReader(responseStream);
// Read the content.
string responseFromServer = reader.ReadToEnd();
//converting json data into array
JavaScriptSerializer ss = new JavaScriptSerializer();
object itm = ss.DeserializeObject(responseFromServer);
In this response stream object gives the json string with multiple values and I am converting this into object using javascriptserializer. At debugging mode I have seen that all the data is there in this object in multiple rows where each rows in itself is also a object .
These rows store information like offer_id, name as keys and there values. I want to write a loop to call this keys and its value to perform further action. But I am unable to call these data in the loop.

Usually the way I would use a JavaScriptSerializer would be to
//Serialise
JavaScriptSerializer js = new JavaScriptSerializer();
string str = js.Serialize(new Thing() { ID = "111" });
//Deserialise
Thing thing = js.Deserialize<Thing>(str);
however if you do not know the Type to convert back to you can
Dictionary<string, object> dic = (Dictionary<string, object>)js.DeserializeObject(str);
foreach (KeyValuePair<string, object> keyValue in dic)
{
keyValue.Key; <-- this is the property name (ID)
keyValue.Value; <-- this is the property value ("111")
}
and then just handle the key value pairs you receive.

Related

.NET API Can't Find Data I Want

I'm trying to save two variables out of a json request but i'm just trying to get the first one working this is my request:
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("https://api.majestic.com/api/json?app_api_key=KEY&cmd=GetIndexItemInfo&items=1&item0=http://www.majestic.com&datasource=fresh");
{
WebResponse response = request.GetResponse();
using (Stream responseStream = response.GetResponseStream())
{
StreamReader reader = new StreamReader(responseStream, Encoding.UTF8);
JObject jObject = JObject.Parse(reader.ReadToEnd());
JToken Trusty = jObject["DataTables"]["Results"]["Data"][2];
var newdomain = new Identifier { domain = model.domain, contact = model.contact, contactname = model.contactname, price = model.price, type = model.type, TrustFlow = Int32.Parse(Trusty.ToString()), CitationFlow = 65, RI = model.RI, MJTopicsID = model.MJTopicsID, UserTableID = model.UserTableID };
ViewBag.newdomain = newdomain;
db.Identifiers.Add(newdomain);
This returns this error:
System.ArgumentOutOfRangeException: 'Index was out of range. Must be non-negative and less than the size of the collection.'
I've also tried
Token Trusty = jObject["DataTables"]["Results"]["Data"]["TrustFlow"][0];
this returns:
'Accessed JArray values with invalid key value: "TrustFlow". Int32 array index expected.'
This is the json I tried separating it myself as on the url it just came as one long line:
{
"Code":"OK","ErrorMessage":"","FullError":"","FirstBackLinkDate":"2017-08-17","IndexBuildDate":"2017-11-20 10:51:56","IndexType":1,"MostRecentBackLinkDate":"2017-11-18","QueriedRootDomains":0,"QueriedSubDomains":0,"QueriedURLs":1,"QueriedURLsMayExist":0,"ServerBuild":"2017-10-25 14:33:44","ServerName":"QUACKYO","ServerVersion":"1.0.6507.24412","UniqueIndexID":"20171120105156-FRESH",
"DataTables":{
"Results":{
"Headers":{
"MaxTopicsRootDomain":30,"MaxTopicsSubDomain":20,"MaxTopicsURL":10,"TopicsCount":3
},
"Data":[{
"RefDomainTypeProtocolHTTPS":"228","CitationFlow":42,"TrustFlow":29,"TrustMetric":29,"TopicalTrustFlow_Topic_0":"Health/Animal","TopicalTrustFlow_Value_0":26,"TopicalTrustFlow_Topic_1":"Business","TopicalTrustFlow_Value_1":25,"TopicalTrustFlow_Topic_2":"Computers/Internet/Domain Names","TopicalTrustFlow_Value_2":24
}
]}}}
What am I doing wrong? Thanks.
Your Data property is an array of size 1. Arrays are 0 index based. So you will access the first item as someArray[0] and second item as someArray[1] and so on
To read the int value stored inside the TrustFlow property of the first item in the Data array, you can do this
int trustFlow = jObject["DataTables"]["Results"]["Data"][0]["TrustFlow"].Value<int>();
This should work for the JSON Data you provided in the question. Keep in mind that this code expects the data to be in that structure . For example, if your Data array does not have any item, or your Results does not have a Data property, the code will crash ( probably with a null reference exception). You can add the null check yourself before trying to access the value as needed.

JSON Deserialize Error: The given key was not present in the dictionary

I'm trying to output JSON to a drop down list in a web form. I've managed to get this far:
WebClient client = new WebClient();
string getString = client.DownloadString("http://myfeed.com/app_feed.php");
JavaScriptSerializer serializer = new JavaScriptSerializer();
dynamic item = serializer.Deserialize<object>(getString);
string name = item["title"];
return name;
This brings back the feed ok but it runs into an error on the line:
string name = item["title"];
Bringing back this error:
Additional information: The given key was not present in the dictionary.
This is a sample of my feed:
{"apps":[{"title":"title1","description":"description1"},
{"title":"title2","description":"description2"},
{"title":"title3","description":"description3"}
So I thought that I was referencing the first title and I was planning to loop through them:
string name = item["title"];
But obviously not!
I have looked on Stackoverflow but I can't find an answer that I can apply to my own code.
title is inside another key apps and its an array so you should iterate it, I show you just select first one using index 0
string name = item["apps"][0]["title"];
you can access all by foreach
foreach (var ap in item["apps"])
{
Console.WriteLine(ap["title"]);
}
First, your JSON is invalid. Second: you need to loop over your items, as it is an array. If you want to access the first one, you could do: item["apps"][0]["title"]
Looping through all items:
var str = #"{""apps"":[{""title"":""title1"",""description"":""description1""},
{""title"":""title2"",""description"":""description2""},
{""title"":""title3"",""description"":""description3""}]}";
var serializer = new JavaScriptSerializer();
dynamic obj = serializer.Deserialize<object>(str);
foreach (var item in obj["apps"])
{
Console.WriteLine("item title: " + item["title"]);
}

Newtonsoft Object serialized to String. JObject instance expected

Hi so am trying to parse this JSON line but i got some others that are like this in files thats why i want to automate this so i can remove the invalid lines to make the file a valid JSON for reading, The problem is that the JSON contains multiple JSON in 1 line
Example:
{"item":"value"}{"anotheritem":"value"}
Is there anyway to remove
{"anotheritem":"value"}
So it turns in to a valid JSON that is readable to start parsing the files
I tried doing using StreamReader cause there in a file i have multiple files that contain these invalid JSON
So i got it to be able to detect the Invalid JSON but for some reason i can't get it to read the JSON so i can use .remove to remove the invalid line
using (StreamReader r = new StreamReader(itemDir))
{
string json = r.ReadToEnd();
if (json.Contains("anotheritem"))
{
JObject NoGood = JObject.FromObject(json);
MessageBox.Show(NoGood.ToString());
}
}
The Error:
Object serialized to String. JObject instance expected.
Thank you all for your time and help.
If each object are side by side without space or any other character, you can convert your string to an json array.
string value = "{\"item\":\"value\"}{\"anotheritem\":\"value\"}";
string arrayValue = "[" + value.Replace("}{", "},{") + "]";
var array = JArray.Parse(arrayValue);
var goopArray = array.OfType<JObject>().Where(o => o.Property("anotheritem") == null);
Edit : see my second answer. More robust solution. More modern. And support dotnet core builtin json serializer.
Json.Net
Even better solution, Json.NET have a builtin feature for this exact scenario. See Read Multiple Fragments With JsonReader
The JsonTextReader have a property SupportMultipleContent that allow to read consecutive items when set to true
string value = "{\"item\":\"value\"}{\"anotheritem\":\"value\"}";
var reader = new JsonTextReader(new System.IO.StringReader(value));
reader.SupportMultipleContent = true;
var list = new List<JObject>();
while (reader.Read())
{
var item = JObject.Load(reader);
list.Add(item);
}
System.Text.Json
If you want to use System.Text.Json, it's also acheivable. They are no SupportMultipleContent property but Utf8JsonReader will do the job for you.
string value = "{\"item\":\"value\"}{\"anotheritem\":\"value\"}";
var bytes = Encoding.UTF8.GetBytes(value).AsSpan();
var list = new List<JsonDocument>();
while (bytes.Length != 0)
{
var reader = new Utf8JsonReader(bytes);
var item = JsonDocument.ParseValue(ref reader);
list.Add(item);
bytes = bytes.Slice((int) reader.BytesConsumed);
}

Read Json object and put the values in a List of string

Platform: C#
IDE: Visual Studio 2010
I am trying to read all the values from json object and put it in the list of string , for which I am doing Json deserialize but it throws me error...
Here is what I have tried
List<string> lstPName = new List<string>();
JavaScriptSerializer strJsonSer = new JavaScriptSerializer();
localhost.Pstats objStats = new localhost.Pstats();
var strJson = objStats.GetAutoCompleteData(txtSearchBox.Text.Trim());
lstPName = strJsonSer.DeserializeObject<string>(strJson);
Here is what the Json object holds
[{"PlayerName":"WA Mota"},{"PlayerName":"Atif Ahmed"}]
So, I need the player name value to be added in the list...
Simple and straightforward solution:
var strJson = "[{\"PlayerName\":\"WA Mota\"},{\"PlayerName\":\"Atif Ahmed\"}]";
var strJsonSer = new JavaScriptSerializer();
var list = new List<string>();
var result = strJsonSer.DeserializeObject(strJson) as object[];
if (result != null)
{
foreach (Dictionary<string, object> x in result)
{
list.Add(x["PlayerName"].ToString());
}
}
Or, if you are preferring LINQ - you can use instead of foreach loop something like:
list = result
.Cast<Dictionary<string, object>>()
.Select(x => x["PlayerName"].ToString())
.ToList();
Key idea: DeserializeObject used for parsing JSON data like yours gives you array of Dictionary<string, object> where key is JSON property name and value is JSON property value. Size of array equals to objects count in your JSON data.

JSON.net access nested arrays, objects

how can I access in this JSON (http://www.pegelonline.wsv.de/webservices/rest-api/v2/stations.json?includeTimeseries=true&includeCurrentMeasurement=true) the nested array like
timeseries.shortname? I tried like this but it doesn't work.
string url = "http://www.pegelonline.wsv.de/webservices/rest-api/v2/stations.json?includeTimeseries=true&includeCurrentMeasurement=true";
HttpWebRequest request = HttpWebRequest.CreateHttp(url);
WebResponse response = await request.GetResponseAsync();
using (Stream stream = response.GetResponseStream())
{
JsonReader reader = new JsonTextReader(new StreamReader(stream));
dynamic info = JArray.Load(reader);
foreach (var item in info)
{
myModel.Add(new ItemModel()
{
uuid = item.uuid,
number = item.number,
city_longname = item.longname,
timeseries = item.timeseries.shortname
});
}
}
The 3 items works, but the last (timeseries) gives the following error: Cannot perform runtime binding on a null reference
The dynamic properties give you JToken objects. Using the Value property on those gives you the string representation. In order to get it type-safe you need to parse/convert. Since you did not provide your ItemModel class details I cannot help you here.
myModel.Add(new ItemModel()
{
uuid = item.uuid.Value,
number = item.number.Value,
city_longname = item.longname.Value
});
The timeseries property is a JArray object. You cannot get to the shortname property directly. You have to choose an index first (item.timeseries[5], for instance, give you the JObject instance you are after). The details regarding getting the actual values in a type-safe manner from above apply here as well.

Categories