Parsing JSON in c# return null value - c#

I am trying to Parse Json in C# . (I am beginner in Json)
WebRequest webRequest = WebRequest.Create(url);
var httpWebRequest = (HttpWebRequest)webRequest;
var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
String responseText = "";
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
responseText = streamReader.ReadToEnd();
}
//
This is Output in responseText :
{
"disclaimer": "Exchange rates provided for informational purposes only and do not constitute financial advice of any kind. Although every attempt is made to ensure quality, no guarantees are made of accuracy, validity, availability, or fitness for any purpose. All usage subject to acceptance of Terms: https://openexchangerates.org/terms/",
"license": "Data sourced from various providers; resale prohibited; no warranties given of any kind. All usage subject to License Agreement: https://openexchangerates.org/license/",
"timestamp": 1454497211,
"base": "EUR",
"rates": {
"INR": 74.42686146,
"USD": 1.0929332
}
}
To get the base from Json
var obj = JObject.Parse(responseText);
String bcur = (string)obj["base"];
Console.WriteLine("base :"bcur.ToString());
Output : base :EUR
similarly to get Rates of INR , I wrote
var obj = JObject.Parse(responseText);
String rte= (string)obj["INR"];
Console.WriteLine("rate:"rte);
it gives me null.
Can anyone tell me what is wrong in my code. or a better way to get the base and rate of the currency .

INR is not in the base object, so you are looking for the INR property in a place where it doesn't exist. You would have to go about it in a two step fashion in order to access the property in . Modifiying your code above, it would look something like this:
var obj = JObject.Parse(responseText);
JObject rates = (JObject)obj["rates"];
string rte = (string)rates["INR"];
Console.WriteLine("rate:" + rte);

Related

How to deserailise JSON Object in C# Without knowing structure

Is it possible to take a JSON object in C# that I read from from another source and convert the contents to files. The problem is I don't know the structure of the incoming objects.
So far I've got this:
var response = await client.GetAsync("https://blahblah/creds" +
"?ApiKey=" + textBox_password.Text +
"&deviceId=" + deviceId +
"&modelNum=" + modelNum);
var res = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
var resJson = JsonConvert.DeserializeObject(res);
this.textBox_Stream.AppendText("responseBody = " + resJson + "\r\n");
Which gives me:
responseBody = {
"statusCode": 200,
"body": {
"modelNum": "42",
"creds": "[{\"deviceid.txt\":\"4DA23E\",\"pac.txt\":\"580795498743\"}]",
"deviceId": "4DA23E"
}
}
What I want to do is create a folder called 4DA23E and place one file inside it for each entry in the creds object.
device.txt will contain 4DA23E
pac.tct will contain 580795498743
etc. I can't figure out a dynamic way to extract the stuff I need. Goes without saying, I am not a C# programmer! So, please be kind.
Don't use JsonConvert.DeserializeObject. That's best when you know the schema of the JSON object and you've made a corresponding C# model.
First, parse the outer response JSON
var res = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
JObject resJson = JObject.Parse(res);
Now pull out the value of the "creds" property and re-parse it.
var credsJsonRaw = resJson["body"]["creds"].Value<string>();
JArray credsJson = JArray.Parse(credsJsonRaw);
Now you can loop through each object in the array, and each property in each object.
foreach (JObject obj in credsJson)
{
foreach (JProperty prop in obj.Properties)
{
Console.WriteLine($"Name = {prop.Name}");
Console.WriteLine($"Value = {prop.Value.Value<string>()}");
}
}
For your example, this prints
Name = deviceid.txt
Value = 4DA23E
Name = pac.txt
Value = 580795498743
One way to deserialise the following json is in two stages. This is because 'creds' is a string.
{
"statusCode": 200,
"body": {
"modelNum": "42",
"creds": "[{\"deviceid.txt\":\"4DA23E\",\"pac.txt\":\"580795498743\"}]",
"deviceId": "4DA23E"
}
}
Here's an example of how to do it. If you're not .NET6 change 'record' to 'class' and if you don't use nullable reference types (on by default in .NET6) remove the appropriate question marks in property definitions.
using System.Text.Json;
using System.Text.Json.Serialization;
var json = File.ReadAllText("data.json");
var o = JsonSerializer.Deserialize<Outer>(json);
if(o?.Body?.Creds == null)
{
throw new Exception("Bad data");
}
var credList = JsonSerializer.Deserialize<List<Dictionary<string, string>>>(o.Body.Creds);
if(credList == null)
{
throw new Exception("Bad data");
}
foreach( var e in credList)
foreach( var kvp in e)
Console.WriteLine($"{kvp.Key} : {kvp.Value}");
record Outer {
[JsonPropertyName("staticCode")]
public int? StaticCode {get; set;}
[JsonPropertyName("body")]
public Body? Body {get; set;}
}
record Body {
[JsonPropertyName("creds")]
public string? Creds {get; set;}
}
This prints
deviceid.txt : 4DA23E
pac.txt : 580795498743

how to upload values as array using c# webclient ? eg items[]="foo" items[]="foo2"

How would you upload a parameter that is an array using c# webclient ?
public string CallWebService(string url, NameValueCollection parametres, string HttpVerb = "GET")
{
WebClient myWebClient = new WebClient();
byte[] myresponse = myWebClient.UploadValues(url, HttpVerb, parametres);
// on essaye de récuopérer l'encoding depuis les headers
// sinon on utilise l'encoding par defaut
Encoding encoding;
encoding = WebUtils.GetEncodingFrom(myWebClient.ResponseHeaders, Encoding.Default);
return encoding.GetString(myresponse);
}
CallWebService(url, new NameValueCollection {
{ "type_pj", "99_AU" },
{ "type_pj", "41_NC" },
{ "type_pj", "41_NC" }
}, "PATCH")
is not understood server side. It is seen as one string "99_AU,41_NC,41_NC".
If I use
CallWebService(url, new NameValueCollection {
{ "type_pj[]", "99_AU" },
{ "type_pj[]", "41_NC" },
{ "type_pj[]", "41_NC" }
}, "PATCH")
it is seen as an Array but it contains only one string ["99_AU,41_NC,41_NC"]
The following curl get its right.
curl -X PATCH \ https://... \ -d 'type_pj%5B%5D=99_AU&type_pj%5B%5D=41_NC&type_pj%5B%5D=41_NC'
The servers sees it as an array of 3 strings ["99_AU","41_NC","41_NC"]
How could I achieve the same using a webclient ?
[EDIT]
It looks like I confused System.Collections.Specialized.NameValueCollection and System.Web.HttpValueCollection (which is a NameValueCollection too but with additionnal features)
var nv = new NameValueCollection {};
nv.Add("type_pj[]", "99_AU");
nv.Add("type_pj[]", "41_NC");
nv.Add("withcomma", "text,with,comma");
nv.Add("type_pj[]", "41_NC");
=> nv["type_pj[]"] = "99_AU,41_NC,41_NC" // = nv[0]
=> nv["withcomma"] = "text,with,comma" // = nv[1]
var hv = HttpUtility.ParseQueryString(string.Empty);
hv.Add("type_pj[]", "99_AU");
hv.Add("type_pj[]", "41_NC");
hv.Add("withcomma", "text,with,comma");
hv.Add("type_pj[]", "41_NC");
string resp = hv.ToString();
=> hv["type_pj[]"] = "99_AU,41_NC,41_NC" // = hv[0]
=> hv["withcomma"] = "text,with,comma" // = hv[1]
In an HttpValueCollection, when you add a new value for an existing key it looks like it concatenate the new value ti the previous but under the hood it is also stored in a array.
=> hv.GetValues("type_pj[]") = ["99_AU","41_NC","41_NC"] // !!! Array of 3 strings
=> hv.GetValues("withcomma[]") = ["text,with,comma"] // !!! Array of 1 strings
The HttpValueCollection has a ToString() method that does the url encoding for you and it preserves the array struct !
=> hv.ToString() ="type_pj%5b%5d=99_AU&type_pj%5b%5d=41_NC&type_pj%5b%5d=41_NC&withcomma=text%2cwith%2ccomma"
So the best solution is probably to use uploadString as suggested by elgonzo. But instead of using Lis you could use an HttpValueCollection which ToString() method will take care of the urlencoding for you.
The problem you are facing is due to using NamedValueCollection. If you inspect the content of your NamedValueCollection in the debugger, you will notice that it aggregates all values under just one key. This is because the name keys you feed to your NamedValueCollection are all identical.
To avoid this, you will have to generate the data payload string manually. To make things simple for the Linq Select statement below in my answer, i switch to a collection that does not organize key/value pairs depending on the uniqueness of the key. For example, you could use a list like this:
var parameters = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string,string>("type_pj[]", "99_AU"),
new KeyValuePair<string,string>("type_pj[]", "41_NC"),
new KeyValuePair<string,string>("type_pj[]", "41_NC")
};
Based on this collection, you could then "manually" compose the data payload string while also making sure both names and values are properly escaped:
var dataPayload = string.Join(
"&",
parameters.Select(kvp => $"{Uri.EscapeDataString(kvp.Key)}={Uri.EscapeDataString(kvp.Value)}")
);
(There are certainly different ways and flavors of how to do this; my example here is just an illustration of the general approach.)
The last step missing is to actually send the encoded payload string and receive the server response. Based on the code in the question, you expect a server response that is text. Fortunately, WebClient has an upload method that both accepts the data to be uploaded as string as well as returning the server response as string: UploadString. Depending on the particular expectations of your server, you might need to specify the content type explicitly, too.
var myWebClient = new WebClient();
myWebClient.Headers.Add(HttpRequestHeader.ContentType, "application/x-www-form-urlencoded");
string responseString = myWebClient.UploadString(url, "PATCH", dataPayload);
As pointed out by #frenchone in the comments, it is also possible to generate the encoded data payload string from a NameValueCollection, albeit with a slightly more complex Linq statement:
var parameters = NameValueCollection
{
{ "type_pj[]", "99_AU" },
{ "type_pj[]", "41_NC" },
{ "type_pj[]", "41_NC" }
}
var dataPayload = string.Join(
"&",
parameters.AllKeys.SelectMany(
key => parameters.GetValues(key).Select(val => $"{Uri.EscapeDataString(key)}={Uri.EscapeDataString(val)}")
)
);

Get property from JSON by string name (already deserialized to class)

I'm using https://currencylayer.com/documentation , Free account's currency conversion API. I let user input output currency, so for example if user input SGD, It'll display the currency conversion for USD to SGD:"USDSGD":1.318504
The way to grab that value is to use dynamic deserializer, and put it to a label. like so:
lblResult.Text=test.quotes.USDSGD.ToString();
But what I want is to get the result regardless of the user selected currency. The other is always USD so I’d like to combine that and the user input currency to get the correct value from the API, like:
var propertyName = "USD" + destinationCurrencyName; // "USDSGD"
lblResult.Text=test.quotes.{propertyName}; // what I'd like
Here I would access the property "USDSGD".
I know that I can use reflection (Get property value from string using reflection in C#) but that seem to be overkill.
This is what the query returns:
{
"success":true,
"terms":"https:\/\/currencylayer.com\/terms",
"privacy":"https:\/\/currencylayer.com\/privacy",
"timestamp":1517629571,
"source":"USD",
"quotes":{
"USDSGD":1.318504
}
}
This is my code - strongly typed version indeed produces expected result, but I'd like to read name of currency (essentially property name of quotes element) from text box:
protected void btnConvert_Click(object sender, EventArgs e)
{
string convertTo = TextBox1.Text.ToString();
var webRequest = (HttpWebRequest)WebRequest.Create("http://apilayer.net/api/live?access_key=MY_ACCESS_KEY&currencies=" + Server.UrlEncode(convertTo) + "&source=USD&format=1");
var webResponse = (HttpWebResponse)webRequest.GetResponse();
if (webResponse.StatusCode == HttpStatusCode.OK)
{
JavaScriptSerializer json = new JavaScriptSerializer();
StreamReader sr = new StreamReader(webResponse.GetResponseStream());
var resString = sr.ReadToEnd();
//var test = JsonConvert.DeserializeObject<Result>(resString);
//lblResult.Text=test.quotes.USDSGD.ToString();
var test2 = JsonConvert.DeserializeObject<dynamic>(resString);
lblResult.Text = test2.quotes.USD+convertTo;
}
}
Currently my code
var test2 = JsonConvert.DeserializeObject<dynamic>(resString);
lblResult.Text = test2.quotes.USD+convertTo;
Returns the value:
SGD
Since the "convertTo" Variable happens to be "SGD".
I want the code to execute lblResult.Text = test2.quotes.USD+convertTo; not return me "convertTo" variable.
Now that I understand your question, you’re trying to concatenation string for accessing a value, not concatenation value and currency.
This can’t be done with dynamic and there’s no need. Deserialize to JObject and use its properties to get the values:
var test2 = JObject.Parse(resString);
var value = (test2[“quotes”] as JObject)[“USD” + convertTo];
Note that this doesn’t check that the data is valid. value is a JToken you can get the value from.
You will want to use JObject to go through the response object:
var response = JObject.Parse(resString);
var quotes = response["quotes"];
lblResult.Text = quotes[ "USD" + convertTo ].Value<string>().ToString();
The indexers of JObject allow you to index directly by strings, which gives you the ability to dynamically select the correct property the users wants.

How to Parse Json data to normal data in C#

I am beginner in c#, I have output from the website like {"result":"Invalid"} with my c# program, It seems to be Json ,I want to display these data as normal string and display it in message box and use those parsed data for validation
Program:
private async void Button_Click(object sender, RoutedEventArgs e)
{
var username = Username.Text;
var password = passbox .Password;
var postMessage = new StringContent(string.Format("username={0}&password={1}", username, password), Encoding.UTF8 , "application/x-www-form-urlencoded");
var response = await (new HttpClient()).PostAsync("http://xxx.xx.net/xx.php", postMessage);
var responseBody = await response.Content.ReadAsStringAsync();
MessageBox.Show( responseBody );
}
I want to know how to display the responseBody as normal string ?
Ideal solution depends on how complex Json string you got. If it has only single property-value pair like posted in question :
{"result":"Invalid"}
I think simple string manipulation logic will bring you the value ("Invalid") easily. Like this naive code :
var jsonString = "{\"result\":\"Invalid\"}";
//remove "{" and "}" from sting
var result = jsonString.Replace("{", "").Replace("}", "");
//separate property name from it's value
var pair = result.Split(':');
//property will contain property name : "result"
var property = pair[0];
//value will contain property value : "Invalid"
var value = pair[1];
Otherwise, if JSON response is more complex, it is not reliable to use string manipulation. I'd suggest to go with Newtonsoft.Json library as also suggested by #Mohammad.
Try using JSON.Net using below code if it returns result as output then
string json = responseBody;
JObject parsed = JObject.Parse(json);
string results = (string)parsed["result"];
Not too sure if this is the best approach... But I'm currently implementing something similar, and using a reader to... read the returned data.
System.IO.StreamReader reader = new System.IO.StreamReader(response.GetResponseStream());
string outputStr = reader.ReadToEnd();
To convert JSON object to string you should serialize it.
I'm using Newtonsoft.Json
After install above package you can use it as the following :
string jsonInString = JsonConvert.SerializeObject(responseBody);
MessageBox.Show(jsonInString);
And for convert json string to an object you can use the following :
ClassName obj = JsonConvert.DeserializeObject<ClassName>(jsonInString);

Parsing JSON result from web link

I'm trying to string data from this JSON Link Click on Link to view
Using JSON.NET. Im able to Deserialize and string the entire thing. But what I need is just values of below
"Warranty":[
{
"EndDate": "ValueIWant",
"ServiceLevelDescription": "ValueIWant"
},
There should be 4 warranty entries from which I need EndDate & ServiceLevelDescription for all and list it in a Multi Line Text box.
Edited: Final Working code
string Serial = "G88NJX1";
WebClient client = new WebClient();
Stream stream = client.OpenRead("https://api.dell.com/support/v2/assetinfo/warranty/tags.json?svctags=" + Serial + "&apikey=1adecee8a60444738f280aad1cd87d0e");
StreamReader reader = new StreamReader(stream);
var jObject = JObject.Parse(reader.ReadLine());
foreach (var o in jObject["GetAssetWarrantyResponse"]["GetAssetWarrantyResult"]["Response"]["DellAsset"]["Warranties"]["Warranty"])
{
Console.WriteLine("Warranty end date: {0}", (string)o["EndDate"]);
Console.WriteLine("Warranty service level description: {0}", (string)o["ServiceLevelDescription"]);
}
Console.ReadLine();
stream.Close();
You can use json.net to parse the json only, rather than deserialize it, then you can query the parsed data, using linq or otherwise. Details here.
This code snippet works in linqpad to output the two values you want from your example json.
var json = #"{'Warranty':[{'EndDate':'ValueIWant','ServiceLevelDescription':'ValueIWant'}]}";
var j = JObject.Parse(json);
foreach(var o in j["Warranty"])
{
Console.WriteLine("Warranty end date: {0}", (string)o["EndDate"]);
Console.WriteLine("Warranty service level description: {0}", (string)o["ServiceLevelDescription"]);
}

Categories

Resources