I call a Weather API - which returns Json response.
My C# Code-
Uri uri1 = new Uri(APIUrl);
WebRequest webRequest1 = WebRequest.Create(uri1);
WebResponse response1 = webRequest1.GetResponse();
StreamReader streamReader1 = new StreamReader(response1.GetResponseStream());
String responseData1 = streamReader1.ReadToEnd().ToString();
dynamic data1 = JObject.Parse(responseData1 )
I get Exception while calling Parse as below-
An unhandled exception of type 'Newtonsoft.Json.JsonReaderException' occurred in Newtonsoft.Json.dll
Additional information: Error reading JObject from JsonReader. Current JsonReader item is not an object: StartArray. Path '', line 1, position 1.
My Analysis-
responseData1 has json strings as-
responseData1="[{\"locationName\":\"Bangalore\",\"subLocationName\":null,\"gid\":\"43295\",\"subStateID\":null,\"subStateName\":null,\"stateID\":\"II\",\"stateName\":\"Indien\",\"latitude\":12.9667,\"longitude\":77.5833,\"altitude\":900,\"zip\":null}\n, {\"match\":\"yes\"}]"
If i check this json in http://jsonlint.com/ - It says valid json.
If i hit my APIUrl directly in browser-
repose in browser is as below-
[{"locationName":"Bangalore","subLocationName":null,"gid":"43295","subStateID":null,"subStateName":null,"stateID":"II","stateName":"Indien","latitude":12.9667,"longitude":77.5833,"altitude":900,"zip":null}, {"match":"yes"}]
My aim is to read the value of property "gid" from the above json.
Can someone help me here?
Thanks!
You're using the JObject class, when you should be using the JArray class, because the JSON you're attempting to parse is an array - not an object:
http://www.newtonsoft.com/json/help/html/ParseJsonArray.htm
It would be better to create a model for this. Then you can simply tell Newtonsoft to deserialize the JSON string instead of using a dynamic type.
First, you would need to create a model like this:
public class WeatherData
{
public string locationName { get; set; }
public string subLocationName { get; set; }
public string gid { get; set; }
public int subStateID { get; set; }
public string subStateName { get; set; }
public string stateID { get; set; }
public string stateName { get; set; }
public double latitude { get; set; }
public double longitude { get; set; }
public int altitude { get; set; }
public string zip { get; set; }
public string match { get; set; }
}
Then deserialize the return JSON as follows:
var data1 = JsonConvert.DeserializeObject<WeatherData>(responseData1);
Or for an array:
var data1 = JsonConvert.DeserializeObject<List<WeatherData>>(responseData1);
Related
I'm trying and failing to write a program that will make an API call and then turn the returned items into objects that fit my model. Specifically I can't make it deserealize, and I suspect it has something to do with how the json is return compared to what my model looks like.
The data I'm trying to get looks like this;
https://api.nasa.gov/planetary/apod?start_date=2022-03-01&end_date=2022-03-08&api_key=DEMO_KEY
As you can see, it consists of an array of items, but there is no name for the array items. When I paste this into the Get-model with Paste JSON as Classes, I get this;
public class GetApodItemsResult
{
public Class1[] Property1 { get; set; }
}
public class Class1
{
public string copyright { get; set; }
public string date { get; set; }
public string explanation { get; set; }
public string hdurl { get; set; }
public string media_type { get; set; }
public string service_version { get; set; }
public string title { get; set; }
public string url { get; set; }
}
My entire code works just fine up until I need to serialize the JSON with this line:
var responseObject = await response.Content.ReadFromJsonAsync<GetApodItemsResult>();
, where I get this message;
System.Text.Json.JsonException: 'The JSON value could not be converted to UnnamedSpaceProject.Models.GetApodItemsResult.
Interestingly I know that the code works on a spotify api call, so the code really should work largely the same, which leads me to believe that the problem is with how the JSON is formatted.
How do I get around that? Because I don't see a way to have the root object contain an unnamed array.
Your GetApodItemsResult class is not a valid class to deserialize the content you get from server, the correct deserialization type will be List<Class1> or Class1[]
var responseObject = await response.Content.ReadFromJsonAsync<List<Class1>>();
I recommend you to use more meaningful name instead of Class1 you can name it Apod (acronym for Astronomy Picture of the Day)
Full working code:
using System.Text.Json;
using System.Text.Json.Serialization;
HttpClient client = new HttpClient();
const string BaseUrl = #"https://api.nasa.gov/";
var response = await client.GetAsync($"{BaseUrl}planetary/apod?start_date=2022-03-01&end_date=2022-03-08&api_key=DEMO_KEY");
if ((response.StatusCode != System.Net.HttpStatusCode.OK))
{
Console.Error.WriteLine("field to fetch data from server");
}
var responseBody = await response.Content.ReadAsStringAsync();
var pictuersList = JsonSerializer.Deserialize<List<Apod>>(responseBody);
Console.WriteLine($"there is {pictuersList?.Count} apod downloaded successflly");
Console.WriteLine("done");
public class Apod
{
[JsonPropertyName("copyright")]
public string Copyright { get; set; } = "";
[JsonPropertyName("date")]
public string Date { get; set; } = "";
[JsonPropertyName("explanation")]
public string Explanation { get; set; } = "";
[JsonPropertyName("hdurl")]
public string Hdurl { get; set; } = "";
[JsonPropertyName("media_type")]
public string MediaType { get; set; } = "";
[JsonPropertyName("service_version")]
public string ServiceVersion { get; set; } = "";
[JsonPropertyName("title")]
public string Title { get; set; } = "";
[JsonPropertyName("url")]
public string Url { get; set; } = "";
}
The object your JSON containing is not some container with the array in it, it IS the array. So, the correct code would be like this:
var responseObject = await response.Content.ReadFromJsonAsync<Class1[]>();
The correct JSON for your code would look like this:
{
"Property1": [{
"copyright": "Jeff DaiTWAN",
"date": "2022-03-01",
"url": "https://apod.nasa.gov/apod/image/2203/DuelingBands_Dai_960.jpg"
}]
}
This line is giving me the error
Cannot deserialize the current JSON object (e.g. {"name":"value"})
From other posts I gather I should not be putting this into a list. However This worked fine for me until I added the avgPx field.
How can I get this information into my List properly?
Does my list of type <OrderRecord> need to include all the fields returned by the JSON?
List<OrderRecord> orderRecord_Single = new List<OrderRecord>();//define and set to null
OrderRecord_Single = JsonConvert.DeserializeObject<List<OrderRecord>>(orderString);
This is one case of my jsonstring. It has the brackets on it.
"[{\"orderID\":\"5dcc6560-9672-958d-010b-7d18c9d523ab\",\"account\":1024235,\"symbol\":\"ETHUSD\",\"timestamp\":\"2020-04-26T18:21:05.703Z\",\"clOrdID\":\"\",\"side\":\"Buy\",\"price\":194.95,\"orderQty\":1,\"ordStatus\":\"New\",\"text\":\"ZT\",\"transactTime\":\"2020-04-26T18:21:05.703Z\",\"avgPx\":null}]"
public class OrderRecord
{
[JsonProperty("orderID")]
public string orderID { get; set; }
[JsonProperty("symbol")]
public string symbol { get; set; }
[JsonProperty("side")]
public string side { get; set; }
[JsonProperty("price")]
public string price { get; set; }
[JsonProperty("orderQty")]
public string orderQty { get; set; }
[JsonProperty("ordStatus")]
public string ordStatus { get; set; }
[JsonProperty("transactTime")]
public string transactTime { get; set; }
[JsonProperty("timestamp")]
public string timestamp { get; set; }
[JsonProperty("avgPx")]
public string avgPx { get; set; }
}
The error occurs because you are trying deserializing a JSON object to a JSON array. So you should provide a JSON array as in input. For the given JSON, add brackets [ ] to the first and last of the JSON string for creating valid JSON array:
var jsonString = "[{\"orderID\":\"8d853505-248d-e515-ee17-ddcd24b5fecb\",\"account\":1024235,\"symbol\":\"XBTUSD\",\"timestamp\":\"2020-04-20T18:25:07.601Z\",\"clOrdID\":\"\",\"side\":\"Buy\",\"price\":6885.5,\"orderQty\":8700,\"ordStatus\":\"Filled\",\"text\":\"ZT\",\"transactTime\":\"2020-04-20T18:22:11.135Z\",\"avgPx\":6885.5}]"
I have JSON string results as follows.
In this response Sometimes sizeKey and sizeName properties are returned as a string. But sometimes both properties are returns inside an array as follows
I am using following code to convert it to object
var assets = jObject["assets"].Children().ToList();
foreach (var item in assets)
{
decorationAssets.Add(item.ToObject<AEDecorationAssets>());
}
And my AEDecorationAssets class is as follows.
public class AEDecorationAssets
{
public string Id { get; set; }
public string Url { get; set; }
public string[] Colors { get; set; }
public string FontKey { get; set; }
public string SizeKey { get; set; }
public string ViewKey { get; set; }
public string FontName { get; set; }
public int Rotation { get; set; }
public string SizeName { get; set; }
public string TextValue { get; set; }
public string EntityType { get; set; }
public string LocationCode { get; set; }
public string LocationName { get; set; }
public string TextEffectKey { get; set; }
public string TextEffectName { get; set; }
public string DecorationMethod { get; set; }
public string NumDecorationColors { get; set; }
}
At the time when "sizeKey" is an array, the above code gives an error. How can I resolve this issue? Is there any JSON property we can use to resolve it?
One way you can do it is by making your SizeKey type an object (i.e. public object SizeKey { get; set; }), then you can switch/case on item.ToObject<AEDecorationAssets>().SizeKey.GetType() to figure out how to handle it (i.e. if String do this, if JArray do that), etc.
If a JSON type is sometime an array, and sometimes a string, you can't really map it simply to a .NET type, as there is none that supports this behavior.
So first you need a datatype that can store this, like and string[] or List<string>.
It could be that JsonConvert will solve this automatically, but otherwise you'll need to write a custom ContractResolver or JsonConverter. Here you can detect if the source property is a string or array. If it's an array, you can use the default deserialization. If it is a string, you need to convert it to an array with a single value.
Simply get json result for which you want to create c# object and then you can valid json response from https://jsonlint.com/ and then you can create c# object of any type json response which you want through http://json2csharp.com. And after get c# object of your json response you only need to deserialization of your json response to c# object which you have created. which will return you expected result.
I have an HttpClient that makes a call to a REST API.
var response = await client.PostAsync("Payments/CreditCard", content);
var contents = await response.Content.ReadAsStringAsync();
When I read the content of the response as a string, I get the following result:
"\"{\\\"ssl_card_number\\\":\\\"41**********9994\\\",\\\"ssl_exp_date\\\":\\\"1219\\\",\\\"ssl_amount\\\":\\\"50.00\\\",\\\"ssl_salestax\\\":\\\"\\\",\\\"ssl_invoice_number\\\":\\\"\\\",\\\"ssl_departure_date\\\":\\\"\\\",\\\"ssl_completion_date\\\":\\\"\\\",\\\"Test\\\":\\\"\\\",\\\"TestField\\\":\\\"TestValue\\\",\\\"ssl_result\\\":\\\"0\\\",\\\"ssl_result_message\\\":\\\"APPROVAL\\\",\\\"ssl_approval_code\\\":\\\"578380\\\",\\\"ssl_cvv2_response\\\":\\\"U\\\",\\\"ssl_avs_response\\\":\\\"G\\\",\\\"ssl_account_balance\\\":\\\"0.00\\\",\\\"ssl_txn_time\\\":\\\"04/09/2018 09:41:01 AM\\\",\\\"ssl_card_type\\\":\\\"CREDITCARD\\\"}\""
When I debug and inspect the value of the contents variable, it contains the following:
When I try to deserialize the string into a C# object using JSON.Net, I receive an exception, because the contents variable can't be converted to my C# object.
However, if I take the string from the Text Visualizer, I'm able to successfully convert it to my C# object.
Here's the class I'm trying to deserialize the string contents into:
public class PaymentResponse
{
public string ssl_account_balance { get; set; }
public string ssl_amount { get; set; }
public string ssl_approval_code { get; set; }
public string ssl_avs_response { get; set; }
public string ssl_card_number { get; set; }
public string ssl_card_type { get; set; }
public string ssl_completion_date { get; set; }
public string ssl_cvv2_response { get; set; }
public string ssl_departure_date { get; set; }
public string ssl_exp_date { get; set; }
public string ssl_invoice_number { get; set; }
public string ssl_result { get; set; }
public string ssl_result_message { get; set; }
public string ssl_salestax { get; set; }
public string ssl_txn_id { get; set; }
public string ssl_txn_time { get; set; }
}
Here's the code I use for deserializing:
paymentResponse = JsonConvert.DeserializeObject<PaymentResponse>(contents);
How can I get my contents variable to have the same value that appears in the Text Visualizer?
The data shown appears to be serialized twice.
In that case it would need to be deserialized twice.
First to string,
var json = JsonConvert.DeserializeObject<string>(contents);
and then to the desired type
var paymentResponse = JsonConvert.DeserializeObject<PaymentResponse>(json);
#Nkosi was right: first deserialize it to string and then to PaymentResponse:
var contents = "\"{\\\"ssl_card_number\\\":\\\"41**********9994\\\",\\\"ssl_exp_date\\\":\\\"1219\\\",\\\"ssl_amount\\\":\\\"50.00\\\",\\\"ssl_salestax\\\":\\\"\\\",\\\"ssl_invoice_number\\\":\\\"\\\",\\\"ssl_departure_date\\\":\\\"\\\",\\\"ssl_completion_date\\\":\\\"\\\",\\\"Test\\\":\\\"\\\",\\\"TestField\\\":\\\"TestValue\\\",\\\"ssl_result\\\":\\\"0\\\",\\\"ssl_result_message\\\":\\\"APPROVAL\\\",\\\"ssl_approval_code\\\":\\\"578380\\\",\\\"ssl_cvv2_response\\\":\\\"U\\\",\\\"ssl_avs_response\\\":\\\"G\\\",\\\"ssl_account_balance\\\":\\\"0.00\\\",\\\"ssl_txn_time\\\":\\\"04/09/2018 09:41:01 AM\\\",\\\"ssl_card_type\\\":\\\"CREDITCARD\\\"}\"";
var contentAsString = JsonConvert.DeserializeObject<string>(contents);
var paymentResponse = JsonConvert.DeserializeObject<PaymentResponse>(contentAsString);
Console.WriteLine(paymentResponse.ssl_card_number);
Check the fiddle.
Here is the solution. Actually we need to take care about the Encoding while deserializing to object. Since the content string of the object would sometimes have other than ASCII charset. It worked fine for me.
var resultBytes = await response.Content.ReadAsByteArrayAsync();
var actualEncodedString = Encoding.UTF8.GetString(resultBytes);
var actualObject = JsonConvert.DeserializeObject<T>(actualEncodedString);
I have a JavaScriptSerializer() that deserialize a JSON from a web service and fails on runtime due to a wrong handling of a list.
This is my class:
public class LoginReply
{
public Userdata userdata { get; set; }
public List<string> errors { get; set; }
}
public class Userdata
{
public string username { get; set; }
public string section{ get; set; }
public string avatar { get; set; }
public string description { get; set; }
public string authkey { get; set; }
}
And I deserilize with:
LoginReply reply = new JavaScriptSerializer().Deserialize<LoginReply>(loginRespose);
I also tried with:
LoginReply reply = new JavaScriptSerializer().Deserialize<List<LoginReply>>(loginRespose);
without any success
(Cannot implicitly convert type
'System.Collections.Generic.List' to
'Redacted.Redacted.LoginReply')
The problem relies in here:
LoginReply reply = new JavaScriptSerializer().Deserialize<List<LoginReply>>(loginRespose);
Youa re trying to deserialize the loginRespose to a list of LoginReply but in other side you are declaring it not as a list.
For the first attemp we have to see the json assigned to loginRespose variable because it might be null or not valid json or does not have the properties like LoginReply class.
If the json is coming like a list of LoginReplys you might have to tro deserializing it to a list of this class like below:
List<LoginReply> reply = new JavaScriptSerializer().Deserialize<List<LoginReply>>(loginRespose);