Newtonsoft.Json Usage in long trees - c#

I'm trying so scrape some info from a JSON response but it fails; I think it may have to do with the way I'm making use of a library I'm new to.
Below is the JSON instance that I'm trying to get data from;
{
"profileChanges":[
{
"changeType":"fullProfileUpdate",
"profile":{
"stats":{
"attributes":{
"allowed_to_receive_gifts":true,
"allowed_to_send_gifts":true,
"ban_history":{},
//This is what I'm trying to scrape the EpicPCKorea string
"current_mtx_platform":"EpicPCKorea",
"daily_purchases":{},
"gift_history":{},
"import_friends_claimed":{},
"in_app_purchases":{
"fulfillmentCounts":{
"2E5AC9924F2247325BBB22AC9AF9965B":1
},
"receipts":[
"EPIC:543a35e70dde4e0aaf56a9e0b76c8f67"
]
},
"inventory_limit_bonus":0,
"mfa_enabled":false,
"monthly_purchases":{},
"mtx_affiliate":"",
"mtx_purchase_history":{},
"weekly_purchases":{}
}
},
"updated":"2018-12-06T14:37:27.797Z",
}
}
],
"profileChangesBaseRevision":31,
"serverTime":"2018-12-30T18:44:35.451Z"
}
Here, my code in C#;
//str4 is the json response that I just posted up.
dynamic json = JsonConvert.DeserializeObject(str4);
string platform = json.profileChanges.profile.stats.attributes.current_mtx_platform;
But it doesn't work at all.
I debugged it and found out this Exception:
'Newtonsoft.Json.Linq.JArray' does not contain a definition for 'profile'
What am I doing wrong and how can I fix it?

As mentioned in the comments under your question, profileChanges is an array so you need to specify which item in the array to access.
Are you sure the the below does not work? It works for me...
string platform = json.profileChanges[0].profile.stats.attributes.current_mtx_platform;

Related

How To Create a JSON Object within an Existing Object in JSON using JObject

I am trying to edit an existing Json File that contains an object called "forge" ("forge" itself is contained within an object called "profiles"), and within that object, I am trying to add another object called resolution that contains height and width. The native application it belongs to can modify and add this element, but I can only seem to be able to read, and write/create all other objects within the forge object except the resolution object and its children.
But no matter how much I read in newtonsoft documentation, nothing appears to be working. This is what I have written so far. Note that this method is just for overwriting all the contents in the "forge" object, and I tired to add the resolution object, but it fails. Anyone know how to do this? (Connection path is the json file)
I think the "resolution" is not array, but an object.
Try this
dynamic forge = new JObject();
forge.Name = "forge";
forge.Type = "Brasil";
dynamic resolutionObj = new JObject();
resolutionObj.Width = "10";
resolutionObj.Height = "100";
forge.resolution = resolutionObj;
You will see anything like this:
{
"Name": "forge",
"Type": "Brasil",
"resolution": {
"Width": "10",
"Height": "100"
}
}

Parsing/Iterating over Json

I'm fairly new to parsing Json with C# and i'm having a little issue i can't work my head around.
My data looks something like this:
{
"languages": {
"ja_lang": {
"data": {
"name": "Japanese"
},
"files": [["ja",
"Japanese File",
"lang_ja.txt"]]
},
"en_lang": {
"data": {
"name": "English"
},
"files": [["en",
"English File",
"lang_en.txt"]]
}
}
}
Now i want to iterate over the items in languages and only work with the one where the object-name starts with "ja_" (in this case it would only work with "ja_lang" and ignore "en_lang"), then extract the name inside data and the "lang_ja.txt" in files.
To Parse the Json in C# i downloaded the Newtonsoft.Json library and came up with this:
dynamic json_obj = JsonConvert.DeserializeObject("json string");
// when debugging language holds { "ja_lang": { "data": { "name": "Japanese" }, "files": [["ja", "Japanese File", "lang_ja.txt"]] } }
foreach (var language in json_obj.languages)
{
// not sure how i can access the object-name
/*if(!language.StartsWith("ja_"))
continue;*/
// Exception: 'Newtonsoft.Json.Linq.JProperty' does not contain a definition for 'data' - Not sure why it is treated as a property?
var name = language.data.name;
var file = language.files[2];
}
I'm sorry for this probably dumb question, but i've been trying to cast it to different types and searched the web for solutions, but i just couldn't figure it out. So if someone could help me out with this i would be really greatful.
Thanks in advance!
Since you're stating in a comment (on an answer that has been deleted) that the data changes so a fixed model won't work, you can still fix what is known:
Here's a LINQPad program that demonstrates:
void Main()
{
var collection = JsonConvert.DeserializeObject<LanguagesCollection>(File.ReadAllText(#"c:\temp\test.json"));
foreach (var keyValuePair in collection.Languages)
if (keyValuePair.Key.StartsWith("ja_"))
keyValuePair.Value.Dump();
}
public class LanguagesCollection
{
public Dictionary<string, JObject> Languages { get; } = new Dictionary<string, JObject>();
}
This will deserialize the outer object, with the "languages" key, and inside you have a dictionary with the keys, "ja_lang", "en_lang", and you can just process the values as you see fit. These are left as JObject which means they will contain whatever json was present as a value for that key in the dictionary.
Using a site like json2sharp you can just pass your json data in and get a ready to use c# model out.
Then you can easily deserialize your json data into that c# model and use the properties for much easier handling:
string jsonData = #"{
'languages': {
'ja_lang': {
'data': {
'name': 'Japanese'
},
'files': [['ja',
'Japanese File',
'lang_ja.txt']]
},
'en_lang': {
'data': {
'name': 'English'
},
'files': [['en',
'English File',
'lang_en.txt']]
}
}
}";
RootObject data = JsonConvert.DeserializeObject<RootObject>(jsonData);
foreach(Languages lang in data.languages) //would work if Languages was a listing
{
}
Although I admit that your Json is a bit strange and that Languages most likly should be a listing and not a property for each language.

Newtonsoft read array in C#

I'm trying to get an entry of a json array into a messagebox but i can't seem to get the entry it always gives me
Newtonsoft.Json.JsonReaderException: 'Unexpected character encountered while parsing value: C. Path '', line 0, position 0.'
No matter what i do here is the json i use:
[
{
"code": 200,
"token": "yourtokenhere",
"id": "youridhere",
"user": "user",
"message": "Successfully connected"
}
]
Here is what i got so far:
string json = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\zero.json";
login fetch = new login();
Newtonsoft.Json.JsonConvert.PopulateObject(json, fetch);
MessageBox.Show(fetch.user);
And here is the C# class i made:
class login
{
public string code;
public string token;
public string id;
public string user;
public string message;
}
Thanks in advance!
EDIT: The full code is available here
Your problem is two-fold.
One issue is that you want to deserialize an array into an object. Other answers here already have addressed this issue.
The other issue, the one responsible for the error in your question, is that you used the Newtonsoft.Json.JsonConvert.PopulateObject method incorrectly. Look at its documentation:
public static void PopulateObject(
string value,
Object target
)
Parameters
value
Type: SystemString
The JSON to populate values from.
target
Type: SystemObject
The target object to populate values onto.
Note that this method expects the Json string data as first argument, not a file path!
So what happens in your code is the variable json gets assigned a file path to your Json file (string json = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\zero.json";). The string variable json will now have a content like #"C:\Users\UserName\AppData\Roaming\zero.json".
Your code passes this string as json data to the PopulateObject() method. But since this string is not json data (it's just the file path), PopulateObject() fails. (Note that the error message complains about the json data starting unexpectedly with a C.)
One possibility of implementing what you want to do is to first read the Json file content into a string, and then pass this to the Json deserializer (in the same way as demonstrated by the other answers):
string filePath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\zero.json";
string json = File.ReadAllText(filePath);
List<login> fetch = Newtonsoft.Json.JsonConvert.DeserializeObject<List<login>>(json);
JSON data is an array and you are trying to deserialize it into an object.
Try below code:
List<login> fetch = Newtonsoft.Json.JsonConvert.DeserializeObject<List<login>>(json);
Please check
JsonConvert.DeserializeObject

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"];

JSON.net Serialize With Namespaces

If I have json that looks something like this: (wrote this by hand, so it may have errors)
{
"http://devserver.somesite.com/someendpoint/1/2/3$metadata#Something.Start": [
{
"Title": "start",
"Endpoint": "https://devserver.somesite.com/someendpoint/1/2/3/start"
}
],
"http://devserver.somesite.com/someendpoint/1/2/3$metadata#Something.Stop": [
{
"Title": "stop",
"Endpoint": "https:// devserver.somesite.com/someendpoint/1/2/3/stop"
}
]
}
Is there any easy, built in way (JSON.net) to have it understand that there’s a namespace in play here? Or is there a way to set a variable or pattern based JsonProperty via an attribute?
I can't have the URL as part of my business object, because that will change from environment to environment.
I know I can create a custom json converter, but before going down that route I’d like to see if there’s something more out of box that handles this. Another option is to get the data via xml and handle that by hand.
Assuming you are taking this as a string that you have received from a web call you can do the following in JSON.NET.
var json = "your string here";
var obj = JObject.Parse(json);
foreach(var ns in obj.Properties) {
var arr = (JArray)ns.Value;
foreach(var obj2 in arr) {
// do you logic here to get the properties
}
}
Another option that James Newton-King provided you can do this, which seems a little cleaner:
var list = JsonConvert.DeserializeObject<Dictionary<string, List<MyClass>>>(json);

Categories