JSON.net Serialize With Namespaces - c#

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);

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"
}
}

Getting nested data from woocomerce with c# and WooCommerceNET

I am having troubles getting nested data from woocomerce in c# (visual studio 2019)...
I am using WooCommerceNET library.
Using variants of this code I can get most data from woocomerce:
var orders = wc.Order.GetAll().GetAwaiter().GetResult();
orders.ForEach(o=> Debug.WriteLine($"ID:{o.Id}"));
But I can not find a way to access data that is nested deeper. For example, how do I get the first_name in shipping address?
"shipping": {
"first_name": "",
"last_name": "",
"company": "",
"address_1": "",
"address_2": "",
"city": "",
"state": "",
"postcode": "",
"country": ""
},
I have tried adapting code from the following topic: c# get values from json , but I did not have any success...
var data = JsonConvert.DeserializeObject<RootObject>(myJSON);
nameArticles=data.articles.FirstOrDefault().description;
So 1. Make sure that you actually have billing information to pull You might not have passed in the customer ID on a order so when your checking it theres no details.
Can you try passing in a per page?
E.g
var p = await wc.Order.GetAll(new Dictionary<string, string>()
{
{"customer", PassInUserId },
{ "per_page", "100" }
});
If your using the Woocom.net Wrapper you dont need to DeserializeObject the Wrapper does that for you.
Also can you try getting a order by Customer and posting the Response.
Here's a Helpful article
https://www.c-sharpcorner.com/article/json-serialization-and-deserialization-in-c-sharp/
But a detailed explanation
In Deserialization, it does the opposite of Serialization, which means it converts JSON string to a custom .Net object. In the following code, it creates an instance of BlogSite class and assigns values to its properties. Then we create an instance of DataContractJsonSerializer class by passing the parameter BlogSite class and creating an instance of MemoryStream class to write object(BlogSite). Lastly it creates an instance of StreamReader class to read JSON data from MemorySteam object.
The Code Example:
string json = "{\"Description\":\"Share Knowledge\",\"Name\":\"C-sharpcorner\"}";
using (var ms = new MemoryStream(Encoding.Unicode.GetBytes(json)))
{
// Deserialization from JSON
DataContractJsonSerializer deserializer = new DataContractJsonSerializer(typeof(BlogSite));
BlogSite bsObj2 = (BlogSite)deserializer.ReadObject(ms);
Response.Write("Name: " + bsObj2.Name); // Name: C-sharpcorner
Response.Write("Description: " + bsObj2.Description); // Description: Share Knowledge
}
Now you handled this yourself
var data = JsonConvert.DeserializeObject<RootObject>(myJSON);
nameArticles=data.articles.FirstOrDefault().description;
With the Wrapper there is no need for it, Its automatically done threw the Task when you call orders or Products or w.e els
So i'm basically just saying that the Wrapper DeserializeObjects so trying to DeserializeObjects wont work I believe, But what you can do is just get the order by ID then just pull the information from the p so you can get the nested data by accesing threw p so p.Metadata[1].key as an example and use it that way

Newtonsoft.Json Usage in long trees

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;

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.

json foreach loop (without json.net)

I'm currently trying to create a small launcher to solve some problems using the existing launcher from minecraft.
I'm trying to read a .json file to get all the informations that i need.
If you need to take a look at the .json file here.
I got it working if i just need a single information like
string clienturl = readJson("//downloads/client/url");
with this:
private string readJson(string element)
{
string json = File.ReadAllText(Path.Combine(appPath + "1.10.2.json"));
var jsonReader = JsonReaderWriterFactory.CreateJsonReader(Encoding.UTF8.GetBytes(json), new System.Xml.XmlDictionaryReaderQuotas());
var root = XElement.Load(jsonReader);
return root.XPathSelectElement(element).Value;
}
The problem now is that i need to get informations for all the other files.
The "element" would be:
libraries/downloads/artifact/path
libraries/downloads/artifact/url
but obviously there is more then one entry for "path" and "url" so i need a foreach loop.
What do i need to change in my code above to make it working with a foreach loop?
Sorry for my bad english, i hope its not to hard to understand.
Small preview of the .json in case you dont want to download the file:
"libraries": [
{
"name": "com.mojang:netty:1.6",
"downloads": {
"artifact": {
"size": 7877,
"sha1": "4b75825a06139752bd800d9e29c5fd55b8b1b1e4",
"path": "com/mojang/netty/1.6/netty-1.6.jar",
"url": "https://libraries.minecraft.net/com/mojang/netty/1.6/netty-1.6.jar"
}
}
},
{
"name": "oshi-project:oshi-core:1.1",
"downloads": {
"artifact": {
"size": 30973,
"sha1": "9ddf7b048a8d701be231c0f4f95fd986198fd2d8",
"path": "oshi-project/oshi-core/1.1/oshi-core-1.1.jar",
"url": "https://libraries.minecraft.net/oshi-project/oshi-core/1.1/oshi-core-1.1.jar"
}
}
},
{
"name": "net.java.dev.jna:jna:3.4.0",
"downloads": {
"artifact": {
"size": 1008730,
"sha1": "803ff252fedbd395baffd43b37341dc4a150a554",
"path": "net/java/dev/jna/jna/3.4.0/jna-3.4.0.jar",
"url": "https://libraries.minecraft.net/net/java/dev/jna/jna/3.4.0/jna-3.4.0.jar"
}
}
}
]
The issue is that your JSON contains an array, and it's not immediately obvious how JsonReaderWriterFactory maps an array to XML elements, given that XML doesn't have the concept of an array.
One way to determine this is to read through the documentation Mapping Between JSON and XML which describes this mapping. But another is simply to determine for ourselves, by using one of the answers from Get the XPath to an XElement? to find out the actual paths for each element. Using this answer, the following code:
var paths = root.DescendantsAndSelf().Select(e => e.GetAbsoluteXPath()).ToList();
Debug.WriteLine(String.Join("\n", paths));
Produces output like:
/root/libraries
/root/libraries/item[1]
/root/libraries/item[1]/name
/root/libraries/item[1]/downloads
/root/libraries/item[1]/downloads/artifact
/root/libraries/item[1]/downloads/artifact/size
/root/libraries/item[1]/downloads/artifact/sha1
/root/libraries/item[1]/downloads/artifact/path
/root/libraries/item[1]/downloads/artifact/url
/root/libraries/item[2]
/root/libraries/item[2]/name
/root/libraries/item[2]/downloads
/root/libraries/item[2]/downloads/artifact
/root/libraries/item[2]/downloads/artifact/size
/root/libraries/item[2]/downloads/artifact/sha1
/root/libraries/item[2]/downloads/artifact/path
/root/libraries/item[2]/downloads/artifact/url
So, as you can see, each array item is placed in a synthetic <item> node.
Thus you can query your paths and urls as follows:
var files = root
.XPathSelectElements("libraries/item/downloads/artifact")
.Select(e => new PathAndUrl { Path = (string)e.Element("path"), Url = (string)e.Element("url") })
.ToList();
Placing the result into a list of the following class:
public class PathAndUrl
{
public string Path { get; set; }
public string Url { get; set; }
}

Categories