Im trying to parse JSON into ListView, but its giving me deserialization error.
This is my model - it's same as api's keys:
public class Currency
{
public string Drzava { get; set; }
public int Sifra_valute { get; set; }
public string Drzava_iso { get; set; }
public int Jedinica { get; set; }
public double Kupovni_tecaj { get; set; }
public double Srednji_tecaj { get; set; }
public double Prodajni_tecaj { get; set; }
}
This is my list of Currencies:
public class CurrencyTable
{
public List<Currency> Results { get; set; }
}
Class for binding with Listview:
public class ShowCurrency
{
static ShowCurrency() {
using (var webClient = new WebClient())
{
String rawJSON =
webClient.DownloadString("http://api.hnb.hr/tecajn/v2/");
CurrencyTable currencyTable =
JsonConvert.DeserializeObject<CurrencyTable>(rawJSON);
}
}
private static List<Currency> currencies;
public static List<Currency> Currencies { get; set; }
public static List<Currency> GetCurrencies() {
return Currencies;
}
}
And i get error at: CurrencyTable currencyTable =
JsonConvert.DeserializeObject(rawJSON);
this is how api looks like:
http://api.hnb.hr/tecajn/v2
The web-service response body starts with this text:
[{"broj_tecajnice":"85","datum_primjene":"2019-05-...
Note how it starts with [ which means it's returning a JSON array directly as its root object and that it is not returning an object with a member named Results (i.e. it is not returning { Results: [ {"broj_tecajnice"... }, { ... } ] }.
Change your code to this:
List<Currency> list = JsonConvert.DeserializeObject<List<Currency>>( rawJSON );
CurrencyTable currencyTable = new CurrencyTable()
{
Results = list
};
Related
I don't know if there is an existing name for that case, but I'm trying to retrieve data from NASA API (https://api.nasa.gov/) and I have a simple challenge to catch a list of objects near earth. Here is the JSON response I have from the GET request I do to "https://api.nasa.gov/neo/rest/v1/feed?...."
{
"links": {
"next": "http://www.neowsapp.com/rest/v1/feed?start_date=2021-07-04&end_date=2021-07-04&detailed=false&api_key=NjgpxgSbYHXyFSBI3HaOhRowtjMZgAKv2t4DMRym",
"prev": "http://www.neowsapp.com/rest/v1/feed?start_date=2021-07-02&end_date=2021-07-02&detailed=false&api_key=NjgpxgSbYHXyFSBI3HaOhRowtjMZgAKv2t4DMRym",
"self": "http://www.neowsapp.com/rest/v1/feed?start_date=2021-07-03&end_date=2021-07-03&detailed=false&api_key=NjgpxgSbYHXyFSBI3HaOhRowtjMZgAKv2t4DMRym"
},
"element_count": 6,
"near_earth_objects": {
"2021-07-03": [
{
"links": {
"self": "http://www.neowsapp.com/rest/v1/neo/3701710?api_key=NjgpxgSbYHXyFSBI3HaOhRowtjMZgAKv2t4DMRym"
},
"id": "3701710",
"neo_reference_id": "3701710",
"name": "(2014 WF497)",
"nasa_jpl_url": "http://ssd.jpl.nasa.gov/sbdb.cgi?sstr=3701710",
"absolute_magnitude_h": 20.23,
"estimated_diameter": {
"kilometers": {
}
And that's the way it is built in Visual Studio (using the Special Paste option for JSON)
public class NearEarthObject
{
public Links links { get; set; }
public int element_count { get; set; }
public Near_Earth_Objects near_earth_objects { get; set; }
}
public class Links
{
public string next { get; set; }
public string prev { get; set; }
public string self { get; set; }
}
public class Near_Earth_Objects
{
public _20210703[] _20210703 { get; set; }
}
public class _20210703
{
public Links1 links { get; set; }
public string id { get; set; }
public string neo_reference_id { get; set; }
public string name { get; set; }
public string nasa_jpl_url { get; set; }
public float absolute_magnitude_h { get; set; }
public Estimated_Diameter estimated_diameter { get; set; }
public bool is_potentially_hazardous_asteroid { get; set; }
public Close_Approach_Data[] close_approach_data { get; set; }
public bool is_sentry_object { get; set; }
}
The question is, inside of the element "near_earth_objects", there is an element called "2021-07-03" (the date of the data I requested), the problem is that I am trying to include it into a DataGridView made in .NET C# (Windows Forms, but that doesn't matters here, I think) and the user wants to get the information by date. So, "2021-07-03" is a valid member just for one day, and the user should be able to get data from multiple days.
So, is there a way in C# to get all child objects inside of near_earth_objects without knowing their names since there will be the option to search for asteroids from date X to Y in my application?
Using System.Text.Json
The API response will map to the following classes
public class Neo
{
public Links Links { get; set; }
public int ElementCount { get; set; }
public Dictionary<string, List<NearEarthObject>> NearEarthObjects { get; set; }
}
public class Links
{
public string Next { get; set; }
public string Prev { get; set; }
public string Self { get; set; }
}
public class NearEarthObject
{
public Links Links { get; set; }
public string Id { get; set; }
public string Name { get; set; }
// Other properties
}
The NearEarthObjects is simply a Dictionary, where the key is the formatted date and value is a List containing NearEarthObject
The PropertyNamingPolicy will allow us to support the API's underscore property naming convention.
public class UnderscoreNamingPolicy : JsonNamingPolicy
{
public override string ConvertName(string name)
{
return name.Underscore();
}
}
Example usage
// using using System.Text.Json;
var response = await new HttpClient().GetStringAsync(url);
var neo = JsonSerializer.Deserialize<Neo>(response, new JsonSerializerOptions
{
PropertyNamingPolicy = new UnderscoreNamingPolicy()
});
foreach(var neos in neo.NearEarthObjects)
{
Console.WriteLine(neos.Key);
}
use System.Text.Json, JsonNamingPolicy
demo code
public class DynamicNamePolicy : JsonNamingPolicy
{
public override string ConvertName(string name)
{
var today = DateTime.Today.ToString("yyyy-MM-dd");
if (name.Equals("DateData")) //model property name
return today; //convert to json string property name
return name;
}
}
//data deserialize
string data = ""; //json string
var obj = JsonSerializer.Deserialize<NearEarthObject>(data, new JsonSerializerOptions
{
PropertyNamingPolicy = new DynamicNamePolicy(),
});
I have A Json file Which can be used for deserialize to Entity framework. For simplify we can assume the Json like this
{
"stat": "val0",
"results": [
{
"datasets": [
"val1",
"val2"
],
"head": "val3"
},
{
"datasets": [
"val4",
"val5"
],
"head": "val6"
}
]
}
And my Entity Classes like
[Serializable]
public class Root
{
[Key]
public int Id { get; set; }
public int stat { get; set; }
public List<Result> results { get; set; }
}
[Serializable]
public class Result
{
[Key]
public int Id { get; set; }
public List<String> _strings { get; set; }
public List<string> Strings
{
get { return _strings; }
set { _strings = value; }
}
[Required]
public string datasets
{
get { return String.Join(",", _strings); }
set { _strings = value.Split(',').ToList(); }
}
public string head{ get; set; }
public virtual root { get; set; }
}
I know Entity Framework does not support primitive types and I know problem causes from my datasets fields. that I found this way to solve String array deserialize issue here. I have tried
URL = "http://...";//Restful webservice address
WebClient client = new WebClient();
String JSON= client.DownloadString(URL);
var dsobj = new System.Web.Script.Serialization.JavaScriptSerializer().Deserialize<RootObject>(json);
But I got
System.InvalidOperationException
Then I have decided to use Newtonsoft
URL = "http://...";//Restful webservice address
WebClient client = new WebClient();
String JSON= client.DownloadString(URL);
var dsobj = JsonConvert.DeserializeObject<Root>(json);
Then I got this error
Newtonsoft.Json.JsonReaderException: 'Unexpected character encountered while parsing value: [. Path 'results[0].senses[0].definition', line 1, position...
I found this but I cant figure it out.
How can Fix these isseus. Any help appreciated.
Your json consist of two unwanted commas, try removing those
try
[Serializable]
public class Root
{
[Key]
public int Id { get; set; }
public string stat { get; set; } // changed to a string
public List<Result> results { get; set; }
}
[Serializable]
public class Result
{
[Key]
public int Id { get; set; }
public List<String> _dataSets { get; set; }
public List<string> dataSets // the JSON array will deserialize into this property
{
get { return _dataSets; }
set { _dataSets = value; }
}
[Required]
public string DatasetsAsString
{
get { return String.Join(",", _dataSets); }
set { _dataSets = value.Split(',').ToList(); }
}
public string head{ get; set; }
public virtual root { get; set; }
}
Edit: stat property has to be a string too.
I'm trying to replicate the functionality in one of MoshHamedani's course on Xamarin Forms.
Here's my code (with a valid, working _url, that returns a json object with escape characters):
public partial class PartnersListPage : ContentPage
{
private const string _url = "xyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyz";
private HttpClient _httpClient = new HttpClient();
private ObservableCollection<Partner> _partners;
public PartnersListPage()
{
InitializeComponent();
}
protected override async void OnAppearing()
{
var jsonObject = await _httpClient.GetStringAsync(_url);
var dotNetObject = JsonConvert.DeserializeObject<List<Partner>>(jsonObject);
_partners = new ObservableCollection<Partner>(dotNetObject);
partnersListView.ItemsSource = _partners;
base.OnAppearing();
}
Partner.cs looks like this:
public class Partner
{
//public int Id { get; set; }
//public string Name { get; set; }
public string ImageUrl { get; set; }
public string WebUrl { get; set; }
}
Postman returns the following:
{
"partners": [
{
"imageUrl": "http://www.abcdefgh.xy//media/1007/3.jpg",
"webUrl": "http://www.abcdefgh.xy/"
},
{
"imageUrl": "http://www.ijklmnop.xy//media/1009/5.jpg",
"webUrl": "https://www.ijklmnop.xy/xy"
},
{
"imageUrl": "http://www.qrstuvxy.xy//media/2623/slsp.svg",
"webUrl": "https://www.qrstuvxy.xy/"
}
]
}
When I hit the JsonConvert.DeserializeObject line, I get the following:
An unhandled exception occured. Why is it not working?
You are deserializing with incorrect type (List<Partner>)
I'm using Json to c# converter in order to determine the class I need - just paste in your json text/data and in will generate the classes for you. For the example for your json text/data you need:
public class Partner
{
public string imageUrl { get; set; }
public string webUrl { get; set; }
}
public class RootObject
{
public List<Partner> partners { get; set; }
}
........
var result = JsonConvert.DeserializeObject<RootObject>(jsonObject);
controller returning single object but you are trying to array deserialize
public class Partner
{
//public int Id { get; set; }
//public string Name { get; set; }
public string ImageUrl { get; set; }
public string WebUrl { get; set; }
}
public class ApiResult
{
List<Partner> Partners {get;set;}
}
and..
var dotNetObject = JsonConvert.DeserializeObject<ApiResult>(jsonObject);
I'm using the Newtonsoft library for parsing JSON:
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
I have my json string and "MyClass" class.
JSON string:
{
"Result":
{
"MyClassList": [
{"Id":1,"Amount":"5,00"},
{"Id":2,"Amount":"10,00"},
{"Id":3,"Amount":"20,00"},
{"Id":4,"Amount":"25,00"}
]
"ReturnValues":
{
"ErrorCode":1,
"ErrorDescription":"Successful"
}
}
}
My Class:
public class MyClass
{
[JsonProperty("Id")]
Int64 Id { get; set; }
[JsonProperty("Amount ")]
string Amount { get; set; }
}
I am getting json data using these classes "GetMyClassList", "RootObject" and "ReturnValues".
List<MyClass> GetMyClassList()
{
JObject jo = new JObject();
List<MyClass> myClassList = new List<MyClass>();
jo.Add("Name", "Name");
jo.Add("Surname", "Surname");
url = "MyUrl";
string responseText = ExecuteHttpRequest(url , "POST",
"application/json", Encoding.UTF8.GetBytes(jo.ToString()), 3000);
myClassList = JsonConvert.DeserializeObject<RootObject>(responseText)
.GetMyClassListResult.MyClassList;
return myClassList;
}
public class ReturnValues
{
public int ErrorCode { get; set; }
public string ErrorDescription { get; set; }
}
public class GetMyClassListResult
{
[JsonProperty("MyClassList")]
public List<MyClass> MyClassList { get; set; }
public ReturnValues ReturnValues { get; set; }
}
public class RootObject
{
public GetMyClassListResult GetMyClassListResult { get; set; }
}
I cannot get this data array (Id and amount).
and I want to take this data and show it in a dataGridView.
The best way to t-shoot this is set breakpoint at the line, where u getting the results from method -> is it filled? This Line:
return myClassList;
I have run Your code with single adjustment -> I have just used the direct JSON (not from web) - code below. This run without issues and I can see all the results parsed out of the JSON.
You have to find if the issue is parsin the JSON, or setting the data to the DataGridTable (which code You have not included at all).
class Program
{
static void Main(string[] args)
{
var result = new Program().GetMyClassList();
foreach (var item in result)
Console.WriteLine($"ID: {item.Id}\tAmount:{item.Amount}");
Console.ReadKey();
}
public List<MyClass> GetMyClassList()
{
List<MyClass> myClassList = new List<MyClass>();
string responseText = "{\"GetMyClassListResult\":{\"MyClassList\":[{\"Id\":1,\"Amount\":\"5,00\"},{\"Id\":2,\"Amount\":\"10,00\"},{\"Id\":3,\"Amount\":\"20,00\"},{\"Id\":4,\"Amount\":\"25,00\"}],\"ReturnValues\":{\"ErrorCode\":1,\"ErrorDescription\":\"Successful\"}}}";
myClassList = JsonConvert.DeserializeObject<RootObject>(responseText)
.GetMyClassListResult.MyClassList;
return myClassList;
}
}
public class MyClass
{
[JsonProperty("Id")]
public Int64 Id { get; set; }
[JsonProperty("Amount")]
public string Amount { get; set; }
}
public class ReturnValues
{
public int ErrorCode { get; set; }
public string ErrorDescription { get; set; }
}
public class GetMyClassListResult
{
[JsonProperty("MyClassList")]
public List<MyClass> MyClassList { get; set; }
public ReturnValues ReturnValues { get; set; }
}
public class RootObject
{
public GetMyClassListResult GetMyClassListResult { get; set; }
}
{"balances-and-info":{"on_hold":[],"available": {"USD":0.93033384},"usd_volume":"243.18","fee_bracket": {"maker":"0.00","taker":"0.60"},"global_usd_volume":"0.09942900"}}
I have this JSON response, and I'm trying to store it in an object, however as you can see "balances-and-info" cannot be used as a variable name. The method I have been using is:
RestClient client = new RestClient("http://currency-api.appspot.com/api/");
RestRequest request = new RestRequest(url);
var response = client.Execute<Currency>(request);
Currency obj = response.Data;
Where obviously the class is a lot easier
public class Currency
{
public string rate { get; set; }
}
So how can I handle this?
String.replace() balances-and-info with balances_and_info
in your code
YourObject deserialized = parseResponse(obj.replace("balances-and-info", "balances_and_info"));
YourObject parseResponse(string response) {
try
{
// https://www.nuget.org/packages/Newtonsoft.Json/
// Json.NET
YourObject ret = JsonConvert.DeserializeObject<YourObject>(response);
return ret;
}
catch (JsonSerializationException)
{
// do something
}
return null;
}
YourObject
Use http://json2csharp.com/ and generate your object (copy response string, replace balances-and-info with balances_and_info and generate)
public class Available
{
public double USD { get; set; }
}
public class FeeBracket
{
public string maker { get; set; }
public string taker { get; set; }
}
public class BalancesAndInfo
{
public List<object> on_hold { get; set; }
public Available available { get; set; }
public string usd_volume { get; set; }
public FeeBracket fee_bracket { get; set; }
public string global_usd_volume { get; set; }
}
public class YourObject
{
public BalancesAndInfo balances_and_info { get; set; }
}