How do I use restsharp to read a Json array - json

I need to read the following piece of code using RestSharp. My problem is how to get the array in the proper structure. How do I need to setup the class that will contain the object to make this work properly?
I would like to deserialize the object "0" and "1" in a List of type AcUserInfo.
Thanks a lot.
Andrea
{
"0":{
"id":"2",
"subscriberid":"2",
"cdate":"2012-09-28 16:49:06",
"sdate":"2012-09-28 16:49:06",
"first_name":"Al",
"last_name":"",
"email":"test#verizon.net"
},
"1":{
"id":"29",
"subscriberid":"29",
"cdate":"2012-10-02 15:08:29",
"sdate":"2012-10-02 15:08:29",
"first_name":"Mark",
"last_name":"",
"email":"test2#verizon.net"
},
"result_code":1,
"result_message":"Success: Something is returned",
"result_output":"json"
}
Here's the class I've created:
public class SubscriberList {
public int result_code { get; set; }
public string result_message { get; set; }
public string result_output { get; set; }
public List<AcUserInfo> row { get; set; }
SubscriberList(){
row = new List<AcUserInfo>();
}
}

Your JSON data does not contain an array, and therefore cannot be deserialized to a List<>.
Either convert your JSON to something like this:
{
[{
"id":"2",
"subscriberid":"2",
"cdate":"2012-09-28 16:49:06",
"sdate":"2012-09-28 16:49:06",
"first_name":"Al",
"last_name":"",
"email":"test#verizon.net"
},
{
"id":"29",
"subscriberid":"29",
"cdate":"2012-10-02 15:08:29",
"sdate":"2012-10-02 15:08:29",
"first_name":"Mark",
"last_name":"",
"email":"test2#verizon.net"
}],
"result_code":1,
"result_message":"Success: Something is returned",
"result_output":"json"
}
Or if you always only have the "0" & "1" element then change your SubscriberList class to match it.

Related

AppSettings Deserialize to an unknown or dynamic class

I'm trying to set up a series of complex app settings in a separate settings.json file - I won't go into detail as to why...
So I have a JSON file which looks like this:
{
"Website": {
"Name": "Website Name",
"api_key": "----------",
"domain": "-----------"
},
"Pages": {
"Index": {
"Name": "Index",
"Widgets": {
"BestSellers": {
"Name": "BestSellers",
"Type": "ProductCollection",
"Data": {
"Limit": "8",
"Sort": {
"SortType": 3
},
"GetFullProducts": true,
"GroupVariations": false
}
}
}
}
}
}
The first section "Website" simply fetches string settings, all working fine.
The section section "Pages" is more complicated. I have classes that look like this:
public class PageSettings
{
public string Name { get; set; }
public Dictionary<String, Widget> Widgets { get; set; }
public class Widget
{
public string Name { get; set; }
public string Type { get; set; }
public Dictionary<String, object> Data { get; set; } // THIS IS THE PROPERTY THIS QUESTION IS ABOUT
}
}
I use this code to deserialise the above:
IConfigurationSection pagessection = root.GetSection("Pages");
if (pagessection.Exists())
{
_Pages = new Dictionary<String, PageSettings>();
pagessection.Bind(_Pages);
}
With the JSON File exactly as above, this will fail. For some reason, the nested Object Sort in the Data property cannot be deserialised as Object:
"Sort": {
"SortType": 3
}
If I take the above nested object out then all the code so far will work. However, there are use cases where I need that nested object.
I have tried using ExpandoObject which is very cool and clever, but because it expects KeyValuePairs, it then only serialises the nested object in Data, ignoring the simple properties Limit, GetFullroduct etc.
So what I need is a form of ExpandoObject which can also be ExpandoString or something?!
Alternatively... I need to be able to get the Data property from the settings.json file in String form and explicitly deserialise it using JsonConvert.Deserialize at the point of use, because at that point I can declare the proper class that it needs to be deserialised to, but i can't seem to find a way to get the IConfigurationSection code to get the value as a string, rather than a JSON object.
I can't find a solution to this, the nested object breaks everything I have tried.
The helpful comment from #Fei Han has helped a little in highlighting the flexibility of the JObject class, so the solution I have come to is this:
The complex class has to be stored as an HTML encoded string in the settings.json file:
"Data": "{"Limit": "8","GetFullProducts":true,"GroupVariations":true, "Sort": {"SortType": 3}}"
it has to be HTMLEncoded because it is the only way I can find to make the ConfigurationBuilder treat it as a string so that I can cast it correctly later.
The corresponding Class for this now has these properties:
public string ModelString { get; set; }
public Newtonsoft.Json.Linq.JObject Model
{
get
{
string s = ModelString.HtmlDecode();
if (s.EmptyStr())
{
return new JObject();
} else {
return JObject.Parse(s);
}
}
}
From this I am able to easily cast my Data to the eventually required class using .ToObject<MyObject>()
For some reason, this works. I am able to deserialise the string to a JObject in this method, but not directly using the Bind command on IConfigurationSection.
If anyone has any tips on why Bind won't do it, that'd be interesting!

incorrect parsing of JSON into ArrayList

I am trying to fill an Android Spinner given some sql generated json in a PHP.
I have already generated with PHP a JSON like this:
{
num: [
{
id: 123
},
{
id: 456
}
]
}
I need to get the Android Client Spinner populated with 123 and 456, but I just get the Spinner populated with only one line (that incidentally contains two ids), I did this:
ArrayList<String> LineArray = new ArrayList<String>();
LineArray.add(responsej.optString("num"));
Spinner myspinner;
myspinner = (Spinner) findViewById(R.id.my_spinner) ;
myspinner.setAdapter(new ArrayAdapter<String>(MainActivity.this,
android.R.layout.simple_spinner_dropdown_item, LineArray));
responsej is the JSONObject that I get with JsonHttpResponseHandler. Any suggestions how to get the Client to understand that each id should get populated?
Make to Model classes like this
Num.class
public class Num
{
public int id { get; set; }
}
SpinnerData.class
public class RootObject
{
public List<Num> num { get; set; }
}
Then parse data to this model

Using Json.net to deserialize a document with references that works with property but not constructor injection [duplicate]

I have this object with a Parent property that reference another object of the same type:
[JsonObject(IsReference = true)]
class Group
{
public string Name { get; set; }
public Group(string name)
{
Name = name;
Children = new List<Group>();
}
public IList<Group> Children { get; set; }
public Group Parent { get; set; }
public void AddChild(Group child)
{
child.Parent = this;
Children.Add(child);
}
}
Serialization works fine and results in json looking like this:
{
"$id": "1",
"Name": "Parent",
"Children": [
{
"$id": "2",
"Name": "Child",
"Children": [],
"Parent": {
"$ref": "1"
}
}
],
"Parent": null
}
But deserialization doesn't work. The Parent property comes back null.
A test looks like this:
[Test]
public void Test()
{
var child = new Group("Child");
var parent = new Group("Parent");
parent.AddChild(child);
var json = JsonConvert.SerializeObject(parent, Formatting.Indented);
Debug.WriteLine(json);
var deserializedParent = (Group) JsonConvert.DeserializeObject(json, typeof(Group));
Assert.IsNotNull(deserializedParent.Children.First().Parent);
}
What am I doing wrong? Any help appreciated!
Using references doesn't work with objects that only have constructors with parameters.
Json.NET has to deserialize all the child values before it creates the parent, it needs those values to pass to the constructor, so there is no valid parent reference to assign to the child.
To expand on James's answer, you can fix this issue by providing a parameterless (default) constructor for Json.Net to use. It can be private if you want, so long as you also mark it with a [JsonConstructor] attribute.
[JsonObject(IsReference = true)]
class Group
{
...
[JsonConstructor]
private Group()
{
}
public Group(string name)
{
Name = name;
Children = new List<Group>();
}
...
}
This arrangement allows Json.Net to create the object without needing all the information up front; it can then use the public properties to fill things in afterward.
Fiddle: https://dotnetfiddle.net/QfqV43
Another way, i found, by being very stubborn is creating a two phase deserialization,
as i describe in the following Deserializing Circular References by Two-Phase deserialization
in general, i create two IContractResolvers, One is used to deserialize only the properties of the Constructor (in case it has parameters).
and in the second phase, I populate the object using regular ContractResolver.

Parse json results in vbnet

how I can parse following code retrieved in a textbox:
{
"items": [
{
"snippet": {
"channelId": "UCcTbyoZjhqoCn4yVawpMFDA",
"title": "Forever - Stratovarius",
"categoryId": "10"
},
"statistics": {
"viewCount": "6180411",
"likeCount": "19060",
"dislikeCount": "342",
"favoriteCount": "0",
"commentCount": "3025"
}
}
]
}
My code for get value title and likeCount:
Dim url As String = "https://www.googleapis.com/youtube/v3/videos?id=8BvV9arABLs&key=KEYAPI&fields=items(id,snippet(channelId,title,categoryId),statistics)&part=snippet,statistics"
Dim json As String = New WebClient().DownloadString(url)
Dim root As JToken = JToken.Parse(json)
Dim sb As New StringBuilder()
For Each item As JToken In root("items")
textbox1.text=sb.AppendLine(item.SelectToken("title") & sb.AppendLine(item.SelectToken("likeCount"))
Next
First, it's better to format marked up data like JSON before you post it.
Like this:
{
"items" : [{
"snippet" : {
"channelId" : "UCcTbyoZjhqoCn4yVawpMFDA",
"title" : "Forever - Stratovarius",
"categoryId" : "10"
},
"statistics" : {
"viewCount" : "6180411",
"likeCount" : "19060",
"dislikeCount" : "342",
"favoriteCount" : "0",
"commentCount" : "3025"
}
}
]
}
As #rufanov said there are a lof of packages for JSON serialization.
As for me, I use Newtonsoft JSON. I use it in C# and will write examples in it, but I strongly believe it should be the same or similar on VB.NET.
Create classes for JSON objects. Pay attention: the members should be names as in JSON object.
public class JItemArray
{
public JItem[] items;
}
public class JItem
{
public JSnippet snippet;
public JStatistics statistics;
}
public class JSnippet
{
public string channelId;
public string title;
public string categoryId;
}
public class JStatistics
{
public string viewCount;
public string likeCount;
public string dislikeCount;
public string favoriteCount;
public string commentCount;
}
Then, you will be able to do
JItemArray itemArray = JsonConvert.DeserializeObject<JItemArray>(yourJsonString);
It will throw JsonReaderException (with explanation in Message) if something fails.
Else, it will return a proper JItem .NET object with all necessary parsed data.
Here it is on NuGet website.
https://www.nuget.org/packages/Newtonsoft.Json/
But if you only need these two values it's pretty good practice to use JToken.
There is many NuGet packages for working with JSON. Use one of them.

Invalid Cast Exception, json, windows phone

Hi Why am i getting an inalid cast exception?
public class RootContainer2
{
[DataMember]
public string StopName { get; set; }
[DataMember]
public string StopId { get; set; }
[DataMember]
public string Stop { get; set; }
[DataMember]
public ObservableCollection<Stops> Stops { get; set; }
}
private void ContentPanel_Loaded(object sender, RoutedEventArgs e)
{
textRouteId.Text = this.NavigationContext.QueryString["name"];
string myvar = textRouteId.Text;
try
{
WebClient webClient = new WebClient();
Uri uri = new Uri("websiteurl");
webClient.OpenReadCompleted += new OpenReadCompletedEventHandler(webClient_OpenReadCompleted);
webClient.OpenReadAsync(uri);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
void webClient_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
DataContractJsonSerializer ser = null;
try
{
ser = new DataContractJsonSerializer(typeof(RootContainer2));
RootContainer2 rootContainer = ser.ReadObject(e.Result) as RootContainer2;
foreach (Stops em in rootContainer.Stops)
{
string df = em.StopName;
string dt = em.StopId;
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Here is the json output which I am trying to read but I get an invalid cast exception.
{"RouteId": "1231", "RouteName":"1 Whitehawk - Mile Oak", "Stops": [ { "StopId":"6882", "StopName":"Swanborough Drive", "OperatorsCode4":"bridmpj", "Lat":"50.8326729229821", "Lng":"-0.103217996656901" } , { "StopId":"6883", "StopName":"Haybourne Road", "OperatorsCode4":"brimapm", "Lat":"50.8317788816436", "Lng":"-0.10486427645364671" } , { "StopId":"6884", "StopName":"Coolham Drive", "OperatorsCode4":"brijtwm", "Lat":"50.829695439856089", "Lng":"-0.10512229365031489" } , { "StopId":"6885", "StopName":"St Cuthmans Church", "OperatorsCode4":"briapdg", "Lat":"50.8283233642578", "Lng":"-0.104808002710342" } ,
Plus the class in stops.cs :
public class Stops
{
public string StopId { get; set; }
public string StopName { get; set; }
}
EDIT:
So after creating my own url and then testing the data, it's something to do with the URL that I was given I think. Just doing further testing.
Edit 2
If i put the data into a text file and debug the data, it works if i do the following.
the end of the feed is like this:
"Lng":"-0.277833998203278", "" } ] }
If i remove the , and "" then it works. but how do i stop it getting there in the first place?
The exception could be caused by missing [DataContract] and [DataMember] attributes, in particular on the Stops class. With the exception of Silverlight 5, DataContract is an opt-in model where all classes and properties that should be serialized have to carry a explicit attribute.
Update:
After your comment, I've looked in more detail into the JSON data you receive. You provide two pieces of JSON. If combined, they look like this:
{
"RouteId": "1231",
"RouteName": "1 Whitehawk - Mile Oak",
"Stops": [
{
"StopId": "6882",
"StopName": "Swanborough Drive",
"OperatorsCode4": "bridmpj",
"Lat": "50.8326729229821",
"Lng": "-0.103217996656901"
},
{
"StopId": "6883",
"StopName": "Haybourne Road",
"OperatorsCode4": "brimapm",
"Lat": "50.8317788816436",
"Lng": "-0.10486427645364671"
},
{
"StopId": "6884",
"StopName": "Coolham Drive",
"OperatorsCode4": "brijtwm",
"Lat": "50.829695439856089",
"Lng": "-0.10512229365031489"
},
{
"StopId": "6885",
"StopName": "St Cuthmans Church",
"OperatorsCode4": "briapdg",
"Lat": "50.8283233642578",
"Lng": "-0.277833998203278",
""
}
]
}
I'm afraid this is simply invalid for JSON. As you found out yourself there is an extra comma and an extra emtpy pair of quotes close to the end. They make the difference between correct and invalid JSON. You can check it with an onlne JSON validator like JSONLint.
The best solution would be if you could fix it on the server side. Otherwise it's probably best to try to fix the data before you passed it into the serializer.
ReadObject() takes a Stream (or some XML-related types) but e.Result is of type object.
Try:
RootContainer2 rootContainer = ser.ReadObject((Stream)e.Result) as RootContainer2;
Edit: On second thoughts, that would probably throw an Invalid Parameter exception rather than an Invalid Cast.
Looks like the object being returned by ReadObject() is not castable to type RootContainer2.