Get value from Json url with a changing variable - c#

I want to get the price of any crypto coin from BitZ api.
I have the code like this:
string coinName;
string jsonURL = "https://apiv2.bitz.com/Market/coinRate?coins=" + coinName;
I will give the variable coinName the value I want for example coinName = "btc" and I want the price in USDT
The problem here is the Json structure it contains the coin name I will end up with tons of code lines if do this for every coin,
public class Btc
{
public string usdt { get; set; }
}
public class Data
{
public Btc btc { get; set; }
}
public class Root
{
public int status { get; set; }
public string msg { get; set; }
public Data data { get; set; }
public int time { get; set; }
public string microtime { get; set; }
public string source { get; set; }
}
Unlike Bittrex api for example which is easier to read using JsonDotNet asset from unity store and :
BittrexJsonUrl = "https://api.bittrex.com/api/v1.1/public/getticker?market=USDT-" + coinName;
and then I use this code to get the data:
private IEnumerator GetData()
{
/////bittrex
UnityWebRequest request = UnityWebRequest.Get(BittrexJsonUrl);
yield return request.SendWebRequest();
if (request.error == null)
{
Bittrex_proccessJsonData(request.downloadHandler.text);
}
else
{
Debug.Log("Something went wrong!!");
}
}
private void Bittrex_proccessJsonData (string _url) {
var _bittrexJsonData = JsonConvert.DeserializeObject<BittrexJsonData>(_url);
bittrexPrice = _bittrexJsonData.result.Last;
}
this works perfectly with with bittrex's Json structure, since it doesnt contain the coin name all I do is change the Json URL.
Now I want to do like the same thing for BitZ's if you have any idea how to please help :) thank you in advance.

For such thing you could use good old SimpleJson.
Here you don't need to implement the entire c# structure but rather access the data field by field via it's ID. You can imagine it like a nested Dictionary like thing.
Simply create that file with given content from the link somewhere in your project and do e.g.
var json = JSON.Parse(the_JSON_string);
var usdt = json["Data"]["bst"]["usdt"].AsFloat;

Related

C# Type safe JSON-Lines Deserialization

Currently I am working with the Shopify GraphQL Bulk Query.
This Query returns a JSON Lines file. Such a file may look like this:
{"id":"gid:\/\/shopify\/Product\/5860091625632","title":"Levis Jeans","description":"Cool Jeans","vendor":"Levis","status":"ACTIVE"}
{"id":"gid:\/\/shopify\/ProductImage\/20289865679008","__parentId":"gid:\/\/shopify\/Product\/5860091625632"}
{"id":"gid:\/\/shopify\/ProductVariant\/37178118963360","title":"32","position":1,"image":null,"selectedOptions":[{"name":"Size","value":"32"}],"inventoryItem":{},"__parentId":"gid:\/\/shopify\/Product\/5860091625632"}
{"available":10,"location":{"id":"gid:\/\/shopify\/Location\/57510625440"},"__parentId":"gid:\/\/shopify\/ProductVariant\/37178118963360"}
{"id":"gid:\/\/shopify\/ProductVariant\/37178118996128","title":"31","position":2,"image":null,"selectedOptions":[{"name":"Size","value":"31"}],"inventoryItem":{},"__parentId":"gid:\/\/shopify\/Product\/5860091625632"}
{"available":5,"location":{"id":"gid:\/\/shopify\/Location\/57510625440"},"__parentId":"gid:\/\/shopify\/ProductVariant\/37178118996128"}
{"available":3,"location":{"id":"gid:\/\/shopify\/Location\/57951518880"},"__parentId":"gid:\/\/shopify\/ProductVariant\/37178118996128"}
{"id":"gid:\/\/shopify\/ProductVariant\/37178119028896","title":"34","position":3,"image":null,"selectedOptions":[{"name":"Size","value":"34"}],"inventoryItem":{},"__parentId":"gid:\/\/shopify\/Product\/5860091625632"}
{"available":5,"location":{"id":"gid:\/\/shopify\/Location\/57510625440"},"__parentId":"gid:\/\/shopify\/ProductVariant\/37178119028896"}
{"available":15,"location":{"id":"gid:\/\/shopify\/Location\/57951518880"},"__parentId":"gid:\/\/shopify\/ProductVariant\/37178119028896"}
Each line of this file is a valid JSON-object and the lines are connected via __parentId with each other.
My Goal is to Deserialize this into C# Classes like this:
class Product
{
public string Id { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public IEnumerable<ProductImage> Images { get; set; }
public IEnumerable<ProductVariant> Variants { get; set; }
}
class ProductImage
{
public string Id { get; set; }
}
class ProductVariant
{
public string Id { get; set; }
public IEnumerable<IDictionary<string, string>> SelectedOptions { get; set; }
public IEnumerable<InventoryLevel> Levels { get; set; }
}
class InventoryLevel
{
public int Available { get; set; }
}
And the output of a potential function performing the deserialization:
var file = new System.IO.StreamReader(#"c:\test.jsonl");
var products = DeserializeJsonL<IEnumerable<Product>>(file);
Shopify suggests to read the file in reverse. I get the Idea.
But I cannot imagine how to deserialize this file in a type safe way. How could I determine if the current line is a ProductVariant, a ProductImage or something else? I cannot influence the JSONL Output to include type information.
I am pretty sure without type information I cannot deserialize it safely. But how should I handle this data then to insert into a database for example?
EDIT the classname in {"id":"gid:\/\/shopify\/Product\/5860091625632"} cannot be used to determine the Type!
I ended up adding some sort of type information to my graphql-query by defining a unique fieldname for each type which may be on a new line in the resulting JSON Lines file.
For that i used GraphQL field aliases:
someQuery {
uniqueFieldAlias : fieldName
}
When i read the file i search on each line for the unique fieldname. Then i deserialize the line into the corresponding class.
using (var file = new StreamReader(await res.Content.ReadAsStreamAsync()))
{
string line;
while ((line = await file.ReadLineAsync()) != null)
{
if (line.Contains("\"uniqueFieldAlias\""))
{
var product = JsonSerializer.Deserialize<Product>(line);
products.Add(product);
continue;
}
if (line.Contains("\"otherUniqueAlias\""))
{
var somethingElse = JsonSerializer.Deserialize<SomeClass>(line);
products[productIndex].Something.Add(somethingElse);
continue;
}
}
}
The idea is inspired by #Caius Jard comments

JSON (deserialized) sends null values to list

Firstly thank you for taking the time to look at this. It's quite alot.
Question:
I'm basically trying to download a json as a string and then deserialize it to a list. The reason why is so i can then call a specific property of that list (in my case 'ips' because it's all i actually need) and insert it into a table if requirements are met.
The problem is that it moves all null values into the array. 114 columns of null, or empty array and i can't figure out why?
I think i'll attach a link to the JSON because its a massive file its here https://endpoints.office.com/endpoints/Worldwide?clientRequestId=b10c5ed1-bad1-445f-b386-b919946339a7
Here is my code:
Getters and setters for JSON
public class GetSetJsonIP {
[JsonProperty("id")]
public int id { get; set; }
[JsonProperty("serviceArea")]
public string ServiceArea { get; set; }
[JsonProperty("serviceAreaDisplayName")]
public string ServiceAreaDisplayName { get; set; }
[JsonProperty("urls")]
public IList<string> urls { get; set; }
[JsonProperty("ips")]
public IList<string> ips { get; set; }
[JsonProperty("tcpPorts")]
public string tcpPorts { get; set; }
[JsonProperty("expressRoute")]
public bool expressRoute { get; set; }
[JsonProperty("category")]
public string category { get; set; }
[JsonProperty("required")]
public bool required { get; set; }
[JsonProperty("notes")]
public string notes { get; set; }
[JsonProperty("udpPorts")]
public string udpPorts { get; set; }
}
List class
public class ConvertJsonIP{
public List<GetSetJsonIP> jsonIpConvert { get; set; }
public List<GetSetJsonIP> jsonIPConvert = new List<GetSetJsonIP>();
}
3.I download the JSON using an empty string called o365IP
o365IP = wc.DownloadString(wc.BaseAddress + "/endpoints/Worldwide?clientRequestId=b10c5ed1-bad1-445f-b386-b919946339a7");
I deserialize using my List to a seperate var
var o365IpVerion = JsonConvert.DeserializeObject<List<ConvertJsonIP>>(o365IP);
This code shows no errors. so i can only assume its a logical one on my part. It should be noted that i had to put the <List< in to stop an error stating that it couldnt convert an object to an array.
Seriously, i've been stuck on this for 3 days so any help on this would be greatly appreciated! Thanks in advance!
the json you have is a list of objects and each of these objects conform to GetSetJsonIp. You should deserialize using List<GetSetJsonIP>
var o365IpVerion = JsonConvert.DeserializeObject<List<GetSetJsonIP>>(o365IP);
public class GetJsonIP works fine.
The reason you must Deserialize into a List<> is because the json object starts with a bracket making the entire object a List or array.
var O365IpVersion = JsonConvert.DeserializeObject<List<GetJsonIP>(O365IP);
There are different ways to fetch the value of a certain property. If you just need ips and want to check the value then update it, then you could loop:
JArray arr = JArray.Parse(O365IP);
foreach (JObject obj in arr.Children<JObject>())
{
foreach (JPRoperty prop in obj.Properties().Where(x => x.Name == "ips"))
{
//use prop.Value and perform tasks
}
}
Or just simply loop like this:
for (int i = 0; i < O365IpVersion.Count; i++)
{
//use O365IpVersion.ElementAt(i).ips

Removing header from a formatted string

I have a formatted log file I'm trying to parse; the file is divided in sections with an header and the data inside each section is formatted with JSON like follows. Link to an extract of the log file here
[UnityCrossThreadLogger]1/8/2019 7:49:19 PM
==> Deck.GetDeckLists(112):
{
"jsonrpc": "2.0",
"method": "Deck.GetDeckLists",
"params": {},
"id": "112"
}
My issue here is manipulating the whole string in a way I get to the section I want and there strip the meaningless data and parse the remaining through Newtonsoft JSON. For now I'm cutting everything I don't need using this function, since the log file is in chronological order and only the latest occurrence of the entry is needed:
//Cut the whole log to the last entry
private static string CutLog(string fromWhereToCut)
{
string log = GetLog();
//In this case fromWhereToCut would be "Deck.GetDeckLists"
string s = log.Substring(log.LastIndexOf(fromWhereToCut));
return s;
}
The problem is the fact it leaves the header in place I need to remove before deserializing the JSON and it's prone to breaking because the name of the sections aren't that unique and they could be repeated further down as non-header titles (as can be seen in my example). Furthermore I don't know how to stop at the end of the section I need before another one begins.
I thought RegEx could be used but this seems way to big even for a RegEx and maybe there's a better solution.
If the Log is the same as the one found in PasteBin, this deserializes fine.
I'm using a support class (JSON_Logs) to contain the extracted data.
The JSON is read from a file in this simulation.
Reading the structure of the data, the most probable candidate to identify the start of the actual data, is the recurring string "Deck.GetDeckLists". In the parsing method it's assigned to a variable called excludedSection.
The data starts right after the last one of those string. I'm using logFile.LastIndexOf(excludedSection) to find the index of the last of these entries, then use this index to identify the first data structure.
JsonConvert.DeserializeObject is then used to deserialize the data into a List of class objects.
I didn't find any problem during the deserialization process.
string searchString = "Deck.GetDeckLists";
List<JSON_Logs.Header> jsonLogs = ParseJsonLog(searchString, "JSON_Logs.txt");
private List<JSON_Logs.Header> ParseJsonLog(string excludedSection, string fileName)
{
string logFile = File.ReadAllText(fileName);
int refIndex = logFile.LastIndexOf(excludedSection);
logFile = logFile.Substring(logFile.IndexOf("[", refIndex));
return JsonConvert.DeserializeObject<List<JSON_Logs.Header>>(logFile);
}
Support class:
public class JSON_Logs
{
public class Header
{
public string id { get; set; }
public string name { get; set; }
public string description { get; set; }
public string format { get; set; }
public string resourceId { get; set; }
public int deckTileId { get; set; }
public MainDeck[] mainDeck { get; set; }
public object[] sideboard { get; set; }
public DateTime lastUpdated { get; set; }
public bool lockedForUse { get; set; }
public bool lockedForEdit { get; set; }
public bool isValid { get; set; }
}
public class MainDeck
{
public string id { get; set; }
public int quantity { get; set; }
}
}
I hope this is what you need. :) Actually, regex finds json in all sections, but I included getting only last section (matches[matches.Count - 1]). Since JToken doesn't have TryParse method, you have to use try/catch:
static void ParseLog()
{
var s = File.ReadAllText(#"C:\log.json");
var pattern =
#"(?s)(?'header'\[\w+\]\d{1,2}/\d{1,2}/\d{4}\s\d{1,2}:\d{1,2}:\d{1,2}\s(A|P)M\r\n" +
#"<?==>?.+?\r\n)" +
#"(?'body'.+?)(?=$|\[\w+\]\d{1,2}/\d{1,2}/\d{4}\s\d{1,2}:\d{1,2}:\d{1,2}\s(A|P)M)";
var matches = Regex.Matches(s, pattern);
if (matches.Count > 0)
{
JToken last_json = null;
try
{
var text = matches[matches.Count - 1].Groups["body"].Value;
last_json = JToken.Parse(text);
WriteLine(last_json.ToString());
}
catch (Exception ex) { WriteLine(ex.ToString()); }
}
else
{
WriteLine("No matches found");
}
}

Download and Parse Json File Server Side

I am learning for the first time how to get a json file from a third party vendor and I am trying to do such with steam. I am trying to retrieve game name and play time of a specific game for a specific user. Based on the online documentation I have read the following code should be working, but the problem is that I am getting back a null. If I take the generated URL and put it in the browser I get back results which means my URL is good, but the way I am parsing it is wrong.
public class SteamMemberViewModel
{
public List<SteamGameViewModel> games { get; set; }
}
public class SteamGameViewModel
{
public int appid { get; set; }
public string name { get; set; }
public int playtime_forever { get; set; }
}
private string GetSteamGame()
{
const int rocketLeagueId = 252950;
var format = string.Format("http://api.steampowered.com/{0}/{1}/v{2}/?key={3}&steamid={4}&include_appinfo=1&format=json", "IPlayerService", "GetOwnedGames", "0001", "ABC", "123");
using (WebClient wc = new WebClient())
{
var json = JsonConvert.DeserializeObject<SteamMemberViewModel>(wc.DownloadString(format));
var rocketLeage = json.games.Where(g => g.appid == rocketLeagueId);
var steamGameViewModels = rocketLeage as SteamGameViewModel[] ?? rocketLeage.ToArray();
if (steamGameViewModels.Count() == 1)
{
var playtime = steamGameViewModels.First().playtime_forever;
return steamGameViewModels.First().name + " - " + playtime;
}
}
return "Steam Game Not Found";
}
The error that I Get is
Value cannot be null.
Parameter name: source
Line 26: var json = JsonConvert.DeserializeObject(wc.DownloadString(format));
Line 27:
Line 28: var rocketLeage = json.games.Where(g => g.appid == rocketLeagueId);
Line 29: var steamGameViewModels = rocketLeage as SteamGameViewModel[] ?? rocketLeage.ToArray();
Line 30: if (steamGameViewModels.Count() == 1)
Source File: e:_websites\Local\Projects\Azularis\Azularis.System.Events\Azularis.System.Events\Controllers\HomeController.cs Line: 28
EDIT:
I have also tried running the code as follows:
var result = wc.DownloadString(format);
var data = JsonConvert.DeserializeObject<SteamMemberViewModel>(result);
var count = data.games.Count();
return count.ToString();
And I still got the same error. result comes back with values though.
JSON FILE EXAMPLE:
{
"response": {
"game_count": 16,
"games": [
{
"appid": 10,
"name": "Counter-Strike",
"playtime_forever": 5019,
"img_icon_url": "6b0312cda02f5f777efa2f3318c307ff9acafbb5",
"img_logo_url": "af890f848dd606ac2fd4415de3c3f5e7a66fcb9f",
"has_community_visible_stats": true
}
]
}
}
Value games inside SteamMemberViewModel is always null.
I would think your issue is that your top object in the JSON is response but you are trying to parse that into the equivalent of the games array. I would think you need to get the array object and then parse so you need to go down a level into the JSON object.
I can't be sure as you do not know if that serializer is performing some recursive work until it finds the object (I doubt it though) but the docs does not seem to do so:
http://www.newtonsoft.com/json/help/html/SerializingJSONFragments.htm
in the example, it clearly states you need to get down to the object you mean to be your top level. And it is not response in your example.
So you'd have to do something like (pseudo-code):
JObject json = JObject.Parse(jsonString);
IList<JToken> array = json["response"]["games"].Children().ToList();
if(array != null)
{
var data = JsonConvert.DeserializeObject<SteamMemberViewModel>(array.ToString());
}
I know you already have an accepted answer. Your issue is easily fixable. Replace SteamMemberViewModel code with below code.
public class SteamMemberViewModel
{
public Response response { get; set; }
}
public class Response
{
public int game_count { get; set; }
public Game[] games { get; set; }
}
public class Game
{
public int appid { get; set; }
public string name { get; set; }
public int playtime_forever { get; set; }
public string img_icon_url { get; set; }
public string img_logo_url { get; set; }
public bool has_community_visible_stats { get; set; }
}

Deserialize JSON string into a list for dropdownlist in C#

I have a windows form application and would like to deserialize a JSON string that I'm getting from a web address so that I can get just two values from it, how would I go about doing this?
Below is the code I have to get the JSON string, and if you go to the URL that it's getting, you can also see the JSON string. I want to just get the item name, and current price of it. Which you can see the price under the current key.
private void GrabPrices()
{
using (WebClient webClient = new System.Net.WebClient())
{
WebClient n = new WebClient();
var json = n.DownloadString("http://services.runescape.com/m=itemdb_rs/api/catalogue/detail.json?item=1513");
string valueOriginal = Convert.ToString(json);
Console.WriteLine(json);
}
}
It's also going to be iterating through a SQLite database and getting the same data for multiple items based on the item ID, which I'll be able to do myself.
EDIT I'd like to use JSON.Net if possible, I've been trying to use it and it seems easy enough, but I'm still having trouble.
Okay so first of all you need to know your JSON structure, sample:
[{
name: "Micheal",
age: 20
},
{
name: "Bob",
age: 24
}]
With this information you can derive a C# object
public class Person
{
public string Name {get;set;}
public int Age {get;set;}
}
Now you can use JSON.NET to deserialize your JSON into C#:
var people = JsonConvert.DeserializeObject<List<Person>>(jsonString);
If you look at the original JSON it is an array of objects, to deal with this I have used List<T>.
Key things to remember, you need to have the C# object mirror in properties that of the JSON object. If you don't have a list, then you don't need List<T>.
If your JSON objects have camel casing, and you want this converted to the C# conventions, then use this:
var people = JsonConvert.DeserializeObject<List<Person>>(
jsonString,
new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() });
First of all you need to create a class structure for the JSON
public class Wrapper
{
public Item item;
}
public class Item
{
public string icon { get; set; }
public string icon_large { get; set; }
public int id { get; set; }
public string type { get; set; }
public string typeIcon { get; set; }
public string name { get; set; }
public string description { get; set; }
public GrandExchange current { get; set; }
public GrandExchange today { get; set; }
public bool members { get; set; }
public GrandExchange day30 { get; set; }
public GrandExchange day90 { get; set; }
public GrandExchange day180 { get; set; }
}
public class GrandExchange
{
public string trend { get; set; }
public string price { get; set; }
}
Then you need to serialize the current item into a Wrapper class
var wrapper = JsonConvert.DeserializeObject<Wrapper>(json);
Then if you want multiple items in a list, you can do so with this code :
// Items to find
int[] itemIds = {1513, 1514, 1515, 1516, 1517};
// Create blank list
List<Item> items = new List<Item>();
foreach (int id in itemIds)
{
var n = new WebClient();
// Get JSON
var json = n.DownloadString(String.Format("http://services.runescape.com/m=itemdb_rs/api/catalogue/detail.json?item={0}", id));
// Parse to Item object
var wrapper = JsonConvert.DeserializeObject<Wrapper>(json);
// Append to list
items.Add(wrapper.item);
}
// Do something with list
It is also worth noting that Jagex limit how many times this API can be called from a certain IP within a time frame, going over that limit will block your IP for a certain amount of time. (Will try and find a reference for this)

Categories