Windows Console Applications VS2105 C# - Using JSON Data - c#

I have at times made it my life's work to avoid API's at all costs (that's a debate for another day) but the time is arriving for this to change, a few months ago I got started on creating an API for my applications, and thanks to this very website, it's worked a charm.
So now I'm creating a simple Windows Console Application, it should do nothing more than get API Data then submit to a database for the primary application to use at a later date.
So far so good or so I thought.
This is what I came up with:
static void Main(string[] args)
{
string pair = "xxx/xxx";
string apiUrl = "http://someURL" + pair;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(apiUrl);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Stream responseStream = response.GetResponseStream();
StreamReader readerStream = new StreamReader(responseStream, System.Text.Encoding.GetEncoding("utf-8"));
string json = readerStream.ReadToEnd();
readerStream.Close();
var jo = JObject.Parse(json);
Console.WriteLine("Pair : " + (string)jo["pair"]);
Console.WriteLine("Open : " + (string)jo["openPrice"]);
Console.WriteLine("Close : " + (string)jo["closePrice"]);
Console.WriteLine("Vol : " + (string)jo["vol"]);
Console.ReadKey();
}
Now this works FANTASTIC for the primary source, but when I change the source (eventually it will be multi source) it fails to work.
After some investigation, it seems the slightly different responses are the culprit.
API Return looks like this
{
"ip":"1.1.1.1","country_code":"AU","country_name":"Australia",
"region_code":"VIC","region_name":"Victoria","city":"Research",
"zip_code":"3095","time_zone":"Australia/Melbourne","latitude":-37.7,
"longitude":145.1833,"metro_code":0
}
The return for an alternative source looks like this
{
"success":true,"message":"",
"result":[
{"MarketName":"BITCNY-BTC","High":8000.00000001,"Low":7000.00000000,
"Volume":0.02672075, "Last":7000.00000000,"BaseVolume":213.34995000,
"TimeStamp":"2017-02-09T08:38:22.62","Bid":7000.00000001,"Ask":9999.99999999,
"OpenBuyOrders":14,
"OpenSellOrders":20,"PrevDay":8000.00000001,"Created":"2015-12-11T06:31:40.653"
}
]
}
As we can see the second return is structured differently, and for this feed I've been unable to work this out, clearly my code works, kind of, and clearly it doesn't.
I've looked about on the net and am still no closer to a solution, partly I don't know what I'm really asking and secondly google only wants to talk webAPI.
If there is someone who can point me in the right direction, I don't want the work done for me per say that solves nothing, I have got to learn to do this one way or another.

As mentioned in the comments, your strings are unrelated. You won't be able to perform the same actions on both JSON strings because they're different.
Your best bet is to work with Deserialization to objects, which is converting a JSON string into an object and working with properties instead of JObject literals.
Putting your first JSON string into Json2Csharp.com, this class structure was produced:
public class RootObject
{
public string ip { get; set; }
public string country_code { get; set; }
public string country_name { get; set; }
public string region_code { get; set; }
public string region_name { get; set; }
public string city { get; set; }
public string zip_code { get; set; }
public string time_zone { get; set; }
public double latitude { get; set; }
public double longitude { get; set; }
public int metro_code { get; set; }
}
You could then make some adjustments to your code to extract the HTTP request functionality, assuming that you'll only be working with JSON strings in this instance, and then simply deserialized the JSON to an object.
An example of a WebRequest() method would be:
private static string WebRequest(string UrlToQuery)
{
using(WebClient client = new WebClient)
{
return client.DownloadString(UrlToQuery);
}
}
(Make sure you catch any errors and deal with unexpected responses, I'll leave that up to you!)
You can then call this method like so:
string JsonResponse = WebRequest(apiUrl);
and deserialize to an object of type RootObject like so:
RootObject deserializedString = JsonConvert.Deserialize<RootObject>(JsonResponse);
You'll then be able to perform something like:
Console.WriteLine($"Country name: {deserializedString.country_name}");
Which will print the value of the country_name property of your deserializedString object.

Related

How to bind JSON response from httpClient.PostAsJsonAsync

I can httpClient.PostAsJsonAsync(path, content) fine.
However, this post returns some JSON with details of the response, eg:
{"StatusCode":200,"AccessCode":"92BEEB285ZB47DA","InternalMessage":null}
I need to access the AccessCode.
How can I do this cleanly and efficiently? Can I create an object like this:
public class GIResponse
{
public string StatusCode { get; set; }
public string AccessCode { get; set; }
public string InternalMessage { get; set; }
}
And map it to the result?
Or how would I just traverse the JSON and pull out the AccessCode?
I have searched quite extensively but surprisingly I can't find anything on Google - perhaps as this is the result from a Post, not a Get.
How can I do this?
Provided that you get the responseText using httpResponse.Content.ReadAsStringAsync, you can use Json.NET's JObject and define it as dynamic:
dynamic j = JObject.Parse(#"{""StatusCode"":200,""AccessCode"":""92BEEB285ZB47DA"",""InternalMessage"":null}");
Console.WriteLine(j.AccessCode);
Also you can use JsonConvert:
var result = JsonConvert.Deserialize<MyModel>(resposeText);
Obviously, if you already have a model, you do not read it as a string and you can simply read it as your model:
var result = httpResponse.Content.ReadAsAsync<MyModel>();

c# multi level json

I am trying to make a simple program that can automate price checking using data from json, however I haven't used json before and I'm not quite sure what I need to do get get the desired result.
Effectively I'm trying to convert this PHP into c#. (http://www.sourcecodester.com/tutorials/php/8042/api-json-parsing-php.html)
<?php
$src = file_get_contents('https://www.g2a.com/marketplace/product/auctions/?id=256');
$json = json_decode($src, true);
foreach ($json as $k=>$v) {
if (is_array($v)) {
foreach($v as $key=>$value) {
if (is_array($value)) {
foreach($value as $arKey => $arValue) {
if ($arKey == 'p') {
echo $arValue . '<br/>';
}
}
}
}
}
}
?>
I've tried a few things such as JsonConvert.DeserializeObject(webJson) and JObject.Parse(webJson), but I'm just not sure where I should be looking or how to go about doing it.
I have the first part:
internal static string GetWebContent(string #ID)
{
var wc = new WebClient();
string response = wc.DownloadString(#"https://www.g2a.com/marketplace/product/auctions/?id=" + #ID);
return response;
}
A response looks like this: (https://www.g2a.com/marketplace/product/auctions/?id=27446)
{"a":{"k_709942":{"c":"pl","tr":3451,"f":"\u00a324.71","fb":"\u00a327.18","ci":"565784","cname":"Marketplace User","p":"24.7098173","pb":"27.18431394","ep":"35.15","epb":"38.67","a":"709942","it":"game","t":"1","sl":"0","l":null,"lt":null,"x":0,"v":"all","so":0,"r":99},"k_763218":{"c":"pl","tr":1120,"f":"\u00a324.74","fb":"\u00a327.22","ci":"6533797","cname":"User #f36726dcd","p":"24.7449664","pb":"27.21946304","ep":"35.20","epb":"38.72","a":"763218","it":"game","t":"0","sl":"0","l":null,"lt":"0","x":0,"v":"all","so":0,"r":92},"k_799750":{"c":"pl","tr":559,"f":"\u00a324.78","fb":"\u00a327.26","ci":"6115711","cname":"Marketplace User","p":"24.7801155","pb":"27.26164196","ep":"35.25","epb":"38.78","a":"799750","it":"game","t":null,"sl":"0","l":null,"lt":null,"x":0,"v":"retail","so":0,"r":98},"k_722082":{"c":"gb","tr":49066,"f":"\u00a324.96","fb":"\u00a327.45","ci":"1047917","cname":"Marketplace User","p":"24.955861","pb":"27.4514471","ep":"35.50","epb":"39.05","a":"722082","it":"game","t":"1","sl":"0","l":null,"lt":"0","x":0,"v":"all","so":0,"r":98},"k_718113":{"c":"pl","tr":5852,"f":"\u00a324.96","fb":"\u00a327.45","ci":"226876","cname":"Marketplace User","p":"24.955861","pb":"27.4514471","ep":"35.50","epb":"39.05","a":"718113","it":"game","t":"1","sl":"0","l":null,"lt":"0","x":0,"v":"all","so":0,"r":98},"k_739155":{"c":"pl","tr":1208,"f":"\u00a325.43","fb":"\u00a327.98","ci":"6540559","cname":"User #1f948a6a66249","p":"25.43316468854","pb":"27.976481157394","ep":"35.30","epb":"38.83","a":"739155","it":"game","t":"0","sl":"0","l":null,"lt":"0","x":0,"v":"all","so":0,"r":89},"k_795049":{"c":"pl","tr":50420,"f":"\u00a325.86","fb":"\u00a328.45","ci":"2498689","cname":"Marketplace User","p":"25.86270778","pb":"28.44968154","ep":"36.79","epb":"40.47","a":"795049","it":"game","t":"1","sl":"0","l":null,"lt":"0","x":0,"v":"all","so":0,"r":99},"k_816132":{"c":"pl","tr":22,"f":"\u00a326.00","fb":"\u00a328.60","ci":"6208533","cname":"Marketplace User","p":"25.99627436","pb":"28.59730776","ep":"36.98","epb":"40.68","a":"816132","it":"game","t":"0","sl":"0","l":null,"lt":"0","x":0,"v":"retail","so":0,"r":0},"k_809925":{"c":"pl","tr":81021,"f":"\u00a326.00","fb":"\u00a328.60","ci":"407513","cname":"Marketplace User","p":"26.00330418","pb":"28.60433758","ep":"36.99","epb":"40.69","a":"809925","it":"game","t":"1","sl":"0","l":null,"lt":"0","x":0,"v":"retail","so":0,"r":100},"k_815898":{"c":"cl","tr":1,"f":"\u00a326.01","fb":"\u00a328.61","ci":"7524623","cname":"Marketplace User","p":"26.010334","pb":"28.6113674","ep":"37.00","epb":"40.70","a":"815898","it":"game","t":null,"sl":"0","l":null,"lt":null,"x":0,"v":"retail","so":0,"r":0},"k_711901":{"c":"pl","tr":12194,"f":"\u00a326.51","fb":"\u00a329.16","ci":"286793","cname":"Marketplace User","p":"26.506689203722","pb":"29.158078610346","ep":"36.79","epb":"40.47","a":"711901","it":"game","t":"1","sl":"0","l":null,"lt":null,"x":0,"v":"all","so":0,"r":99},"k_748710":{"c":"pt","tr":66460,"f":"\u00a326.65","fb":"\u00a329.32","ci":"440288","cname":"Marketplace User","p":"26.650786454082","pb":"29.316585585742","ep":"36.99","epb":"40.69","a":"748710","it":"game","t":"1","sl":"0","l":null,"lt":"0","x":0,"v":"all","so":0,"r":100},"k_709464":{"c":"pl","tr":121341,"f":"\u00a327.02","fb":"\u00a329.72","ci":"1072530","cname":"User #3285e5f8dfcb2","p":"27.0182344425","pb":"29.72005788675","ep":"37.50","epb":"41.25","a":"709464","it":"game","t":"1","sl":"0","l":null,"lt":"0","x":0,"v":"retail","so":0,"r":100},"k_709805":{"c":"pl","tr":11708,"f":"\u00a328.09","fb":"\u00a330.90","ci":"1043113","cname":"User #ca1965d0354a","p":"28.091758957682","pb":"30.901655339702","ep":"38.99","epb":"42.89","a":"709805","it":"game","t":"1","sl":"0","l":null,"lt":null,"x":0,"v":"retail","so":0,"r":100},"k_725839":{"c":"es","tr":1,"f":"\u00a331.99","fb":"\u00a335.18","ci":"7023396","cname":"Marketplace User","p":"31.985681","pb":"35.1842491","ep":"45.50","epb":"50.05","a":"725839","it":"game","t":null,"sl":"0","l":null,"lt":null,"x":0,"v":"retail","so":0,"r":0},"k_0":{"f":"\u00a332.33","fb":"\u00a335.56","p":"32.33014218","pb":"35.563156398","ep":"45.99","epb":"50.59","a":0,"c":"","rc":"","r":"","tr":0,"t":1,"so":0,"x":0,"n":"G2A.com"}},"w":0}
Any help with will greatly appreciated.
Thanks in advace
So Json is a way for two languages to pass objects to each other. It's just a way to encode an object, so the first part would be to create an object that matches the Json encoding. I was unable to see your example, so I will give you one of my own.
{"Aggregates": [{"ColumnName": "Some Value", "AggregateFunction": "Some Other Value"}], "GroupBy": true}
I would then create a class like this one.
public class JsonAggregates
{
public List<Aggregate> Aggregates { get; set; }
public string GroupBy { get; set; }
}
public class Aggregate
{
public string ColumnName {get; set;}
public string AggregateFunction {get; set;}
}
You can then encode the Json to this new data type with the following code.
using (Stream s = GenerateStreamFromString(json))
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(JsonAggregates));
JsonAggregates aggregate = (JsonAggregates)serializer.ReadObject(s);
}

RESTAPI body parameters are passed null when calling in c#

I am trying to call a rest api method from c#. Problem is for all content types it passes null to body parameter.I shared my code below.Apart from this code I have tried to write body parameter to request as stream.It didn't work either. I have also tried 'application/x-www-form-urlencoded' as content type.
Calling rest api method from c# sample:
string token = Server.UrlEncode("v0WE/49uN1/voNwVA1Mb0MiMrMHjFunE2KgH3keKlIqei3b77BzTmsk9OIREken1hO9guP3qd4ipCBQeBO4jiQ==");
string url = "http://localhost:2323/api/Applications/StartProcess?token=" + token;
string data = #"{""ProcessParameters"": [{ ""Name"":""flowStarter"",""Value"": ""Waffles"" }],
""Process"": ""RESTAPISUB""}";
System.Net.Http.HttpClient client = new System.Net.Http.HttpClient();
client.BaseAddress = new System.Uri(url);
byte[] cred = UTF8Encoding.UTF8.GetBytes("username:password");
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", Convert.ToBase64String(cred));
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
System.Net.Http.HttpContent content = new StringContent(data, UTF8Encoding.UTF8, "application/json");
HttpResponseMessage messge = client.PostAsync(url, content).Result;
string description = string.Empty;
if (messge.IsSuccessStatusCode)
{
string result = messge.Content.ReadAsStringAsync().Result;
description = result;
}
Rest api Method:
[HttpPost]
[ActionName("StartProcess")]
public int StartProcess([FromUri]string token,[FromBody]WorkflowStartParameters parameters)
{
try
{
LoginInformation info = CasheProcesses.ReadCashe(token);
eBAWSAPI api = Service.GetWSService();
WorkflowProcess proc = api.StartProcess(info.Id, info.Password, info.ImpersonateUserId, info.Language, parameters);
return proc.ProcessId;
}
catch (Exception ex)
{
throw new Exception("An error occured when starting process,exception detail:" + ex);
}
}
WorkflowStartParameters class structure:
public class WorkflowStartParameters
{
public WorkflowParameter[] ProcessParameters;
public string Process { get; set; }
}
public class WorkflowParameter
{
public string Name { get; set; }
public string Value { get; set; }
}
I have searched this problem a lot. It seems as a very common problem. I just found this solution working properly, passing request parameter to rest api method and reading body parameter from there. But it is not a valid solution for me.
If you have any idea,feel free to share.
Thanks,
Zehra
I don´t know if it can solve your problem, but let me try.
I guess you don´t have to utilize Server.UrlEncode in your call, but:
Dim myUri As New Uri(Token)
And I guess you must not encode also your username and password - try pass them as string.
Your problem appear to be here:
public class WorkflowStartParameters
{
public WorkflowParameter[] ProcessParameters; <---- needs get/set
public string Process { get; set; }
}
This needs to be a public property to serialize properly. Currently you have it set up as a public field. Just add { get; set; } and give that a try. I would also look into serializing with Newtonsoft.Json to ensure your object is properly serialized. Trying to do it with escape strings will be messing the more data you are sending.
By the way there can be issues sometimes serializing arrays, I would change that to :
public List<WorkflowParameter> ProcessParameters{get;set;}
Finally I have achieved to send filled out data to server. It was about serialization problem. But it didn't work with json serialization before send data. I have added DataContract attribute to my class and it works properly.
Unfortunately still I couldn't figure out this when I make ajax calls from java script it works without DataContract attribute but if I call it in c# it needs DataContract attribute. If someone share the information about this I would appreciate!
I am sharing new class structure, everything else but this still same:
[Serializable]
[DataContract]
public class WorkflowParameter
{
[DataMember]
public string Name { get; set; }
[DataMember]
public string Value { get; set; }
}
[Serializable]
[DataContract]
public class WorkflowStartParameters
{
[DataMember]
public WorkflowParameter[] ProcessParameters { get; set; }
[DataMember]
public string Process { get; set; }
}

RestSharp list of non primitives contain all null values on deserialization

I am trying to serialize a list over a RestSharp request. I am getting the correct number of items returned in the list, but their values are all blank. I've tried a lot of different attempts of Json annotations at JsonConvert, but this is the closest I have to working.
public string updateRewards(List<Reward> rewards)
{
RestRequest request = new RestRequest(updateRewardsUrl, Method.POST);
request.RequestFormat = DataFormat.Json;
request.AddParameter("rewards", JsonConvert.SerializeObject(rewards));
RestResponse response = (RestResponse)client.Execute(request);
...
}
[JsonObject]
public class Reward
{
[JsonProperty("id")]
public int id { get; set; }
[JsonProperty("reward")]
public string reward { get; set; }
[JsonProperty("title")]
public string title { get; set; }
}
On the other endpoint...
public object Post(UpdateRewardsRequestDTO updateRewardsRequest)
{
...handle request...
}
[Route("/Rewards/updateRewards", "POST")]
public class UpdateRewardsRequestDTO : IReturn<UpdateRewardsResponseDTO>
{
public List<Reward> rewards { get; set; } //different Reward class, but exact same code as above
}
Sample RestRequest parameters
- System.Collections.Generic.List<RestSharp.Parameter>
+ [0] {rewards=[{"id":0,"reward":"test","title":"test2"}]} RestSharp.Parameter
Sample request received on the other endpoint
- updateRewardsRequest
- rewards Count = 1
- [0]
id 0 int
reward null string
title null string
Could the problem be that two different instances of Reward are causing it to be unable to convert from one to the other?
I managed to get it working with a little hack.
The code on the first endpoint remains the same; the list of rewards is serialized using JsonConvert.SerializeObject(rewards).
On the second endpoint, I define the type of the rewards as a string instead of a List<Reward>. It shows up as an escaped json string. From there, I explicitly use JsonConvert.DeserializeObject<List<Reward>>(rewards) to convert into the list.

Dealing with fanart.tv webservice response JSON and C#

I am trying to use the fanart.tv webservice API but have a couple of issues.
I am using Json.Net (Newtonsoft.Json) and with other web-services I have de-serialized the JSON reponses into C# objects directly.
The issue here is that the element names are changing. Eg. if I search for artist thumbs for Metallica you get
{"Metallica":{"mbid_id":"65f4f0c5-ef9e-490c-aee3-909e7ae6b2ab","artistthumb": [{"id":"36181","url":"http://assets.fanart.tv/fanart/music/65f4f0c5-ef9e-490c-aee3-909e7ae6b2ab/artistthumb/metallica-4fd83b0129f83.jpg","likes":"1"},...]}}
So the root element is called Metallica. Obviously search for another artist and you get a different element name. After attempting to deserialize this to an object I gave up and as in reality all I needed was a list of strings (the urls) I tried to process the JSON
var obj = _downloader.Download<JObject>(url);
if (obj != null)
{
if (obj.HasValues)
{
var fanartArtist = (JProperty)obj.First;
if (fanartArtist.HasValues)
{
var thumbs = fanartArtist.Value[SearchSubTypeToString(subType)];
if (thumbs.HasValues)
{
thumbUrls.AddRange(thumbs.Select(thumb => thumb["url"].ToString()));
}
}
}
}
which works fine when there is a response but if there are no thumbs the web-service returns null and this code fails with
Unable to cast object of type 'Newtonsoft.Json.Linq.JValue' to type 'Newtonsoft.Json.Linq.JObject'.
To complicate matters slightly I am sort of limited by the application and ideally I need to use
JsonConvert.DeserializeObject<TE>(json);
So the question is what what is the best approach to solve both of these issues?
Try this:
First, define objects to hold the data deserialized from the JSON:
class Artist
{
public Guid mb_id { get; set; }
public List<Thumb> artistthumb { get; set; }
}
class Thumb
{
public int id { get; set; }
public string url { get; set; }
public int likes { get; set; }
}
You can then deserialize it like this (where json is a string containing the JSON data from the web service):
Dictionary<string, Artist> artists =
JsonConvert.DeserializeObject<Dictionary<string, Artist>>(json);
Once deserialized, you can access the data like this:
foreach (KeyValuePair<string, Artist> kvp in artists)
{
Console.WriteLine("Urls for " + kvp.Key + ":");
foreach (Thumb thumb in kvp.Value.artistthumb)
{
Console.WriteLine(thumb.url);
}
}
Assuming the data you showed in your question, the output would look like this:
Urls for Metallica:
http://assets.fanart.tv/fanart/music/65f4f0c5-ef9e-490c-aee3-909e7ae6b2ab909e7ae6b2ab/artistthumb/metallica-4fd83b0129f83.jpg
.

Categories