This is my first time using json.net and I can't figure it out. Here is my code below.
// Constructor
public MainPage()
{
InitializeComponent();
}
private void btnRefreshTweets_Click(object sender, RoutedEventArgs e)
{
string ServerURL = #"http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Specialty/ESRI_StateCityHighway_USA/MapServer/1/query?text=e&geometry=&geometryType=esriGeometryPoint&inSR=&spatialRel=esriSpatialRelIntersects&relationParam=&objectIds=&where=&time=&returnCountOnly=false&returnIdsOnly=false&returnGeometry=false&maxAllowableOffset=&outSR=&outFields=&f=json";
WebClient webClient = new WebClient();
webClient.DownloadStringCompleted += new DownloadStringCompletedEventHandler(webClient_DownloadStringCompleted);
webClient.DownloadStringAsync(new Uri(ServerURL));
}
void webClient_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
if (e.Error != null)
{
return;
}
List<Attributes> tweets = JsonConvert.DeserializeObject<List<Attributes>>(e.Result);
this.lbTweets.ItemsSource = tweets;
}
public class Attributes
{
public string STATE_NAME { get; set; }
}
I can't deserialize the STATE_NAME attributes. What am I missing?
I keep getting this error
"Cannot deserialize JSON object into type
'System.Collections.Generic.List`1[WPJsonSample.MainPage+Attributes]'.
Line 1, position 20."
Here is your class structure ( I used http://json2csharp.com/)
public class FieldAliases
{
public string STATE_NAME { get; set; }
}
public class Field
{
public string name { get; set; }
public string type { get; set; }
public string alias { get; set; }
public int length { get; set; }
}
public class Attributes
{
public string STATE_NAME { get; set; }
}
public class Feature
{
public Attributes attributes { get; set; }
}
public class RootObject
{
public string displayFieldName { get; set; }
public FieldAliases fieldAliases { get; set; }
public List<Field> fields { get; set; }
public List<Feature> features { get; set; }
}
IF you are trying to hit that endpoint, you should not be manually submitting the query, you should use the ArcGIS WP7 SDK (it's FREE!). Then use the QueryTask.
(if you just need help with parsing JSON, see below)
QueryTask queryTask = new QueryTask("http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Specialty/ESRI_StateCityHighway_USA/MapServer/1/");
queryTask.ExecuteCompleted += QueryTask_ExecuteCompleted;
queryTask.Failed += QueryTask_Failed;
ESRI.ArcGIS.Client.Tasks.Query query = new ESRI.ArcGIS.Client.Tasks.Query();
query.Text = "e";
query.ReturnGeometry = false;
queryTask.ExecuteAsync(query);
private void QueryTask_ExecuteCompleted(object sender, ESRI.ArcGIS.Client.Tasks.QueryEventArgs args)
{
FeatureSet featureSet = args.FeatureSet
// use the featureSet to do something. It contains everything you need
}
If for whatever reason, you do not want to use the QueryTask, you can still use the FromJson method of the FeatureSet
void webClient_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
var featureSet = ESRI.ArcGIS.Client.Tasks.FeatureSet.FromJson(e.Result);
// Use it
}
If you need help with JSON, here are some key concepts.
1) Curly braces represent an object
2) square brackets represent an array.
3) properties are separated by commas
When using JSON.NET, you should add the JsonProperty attribute to a property. This way you can maintain proper names even if the json sucks
[JsonProperty("STATE_NAME")]
public string StateName { get; set; }
The JSON returned from that url is:
{
"displayFieldName": "STATE_NAME",
"fieldAliases": {
"STATE_NAME": "STATE_NAME"
},
"fields": [
{
"name": "STATE_NAME",
"type": "esriFieldTypeString",
"alias": "STATE_NAME",
"length": 25
}
],
"features": [
{
"attributes": {
"STATE_NAME": "Maine"
}
}
}
So, we can see here the root is an object, not an enumerable like a List<>
You'll have to fix the class structure to match the JSON, or access it with Linq queries (there are some samples of this in the json.net website).
Related
sorry for my bad english. But i need a little help with this method (ToObject)
I have this class
namespace Proyects
{
public class AProductType
{
public DateTime CreationDate { get; set; }
public string Product { get; set; }
}
public class AProduct
{
public AProductType A_ProductType { get; set; }
}
public class AProductPlantType
{
public string SerialNumberProfile { get; set; }
}
public class ToPlant
{
public List<AProductPlantType> A_ProductPlantType { get; set; }
}
public class AProductDescriptionType
{
public string Language { get; set; }
public string Product { get; set; }
public string ProductDescription { get; set; }
}
public class ToDescription
{
public List<AProductDescriptionType> A_ProductDescriptionType { get; set; }
}
public class Root
{
public AProduct A_Product { get; set; }
public ToPlant to_Plant { get; set; }
public ToDescription to_Description { get; set; }
}
}
I am currently using the Root one to save a Jtoken in there. But i cant save the data on the propieties from Root class.
For example:
var object= myJson.ToObject<Root>();
If i try to save data on the propiety Product from AProductType, i cant access there using using ToOject. I try someting like this
var object= myJson.ToObject<Root>().A_Product.A_ProductType.Product;
And dont work, object var become null. I need some way to save the data around this complex object saving then in the propietes from Root.
Really sorry for my english, Thanks!!!
Edit: Json file
{
"A_Product": {
"A_ProductType": {
"CreationDate": "2020-01-17T00:00:00",
"Product": "158"
}
},
"to_Plant": {
"A_ProductPlantType": [
{
"SerialNumberProfile": "E001"
}
]
},
"to_Description": {
"A_ProductDescriptionType": [
{
"Language": "EN",
"Product": "158",
"ProductDescription": "Terminal LaP (nro de serie + equipo)"
},
{
"Language": "ES",
"Product": "158",
"ProductDescription": "Terminal LaP"
}
]
}
}
Edit 2:
private static List<string> retrieveData(JObject ob, List<Root> listaObjetos)
{
List<string> ListaCodigoProducto = new List<string>();
Root objetoRot = new Root();
var A_Product = ob["A_Product"];
if (A_Product.HasValues)
{
var validacion = ob["A_Product"]["A_ProductType"];
if (validacion.Type == JTokenType.Object)
{
var objeto = validacion.ToObject<AProductType>();
ListaCodigoProducto.Add(objeto.Product);
objetoRot.A_Product.A_ProductType.Product = objeto.Product;
listaObjetos.Add(objetoRot);
}
When i try to save the product number on
objetoRot.A_Product.A_ProductType.Product
It shows NullReference exception, i cant access to the propiety in the Root object
The deserializing code is working just fine. Your problem is that you're accessing objects that aren't there.
When you say Root objetoRot = new Root();, you are creating a new, empty Root. Its A_Product value will be null. A few lines down, you are saying objetoRot.A_Product.A_ProductType.Product = objeto.Product;. But you can't get objetoRot.A_Product.A_ProductType because there is no objetoRot.A_Product to access properties on.
for two days I have been trying to understand how to move this JSON to an object in C#. I read a lot of topics and tried several ways to solve my problem, but still haven't solved it.
My JSON looks like this (cropped).
{
"data": [{
"id": 5643793,
"title": "It's a Title",
"description": "It's a Description.",
"tags": "#tag1 #tag2 #tag3 #tag4",
"source_url": "https:\/\/p.dw.com\/p\/3geny",
"vote_count": 120,
"bury_count": 17,
"comments_count": 33,
"related_count": 0,
"date": "2020-08-10 09:43:32",
"author": {
"login": "lnwsk",
"color": 2,
"avatar": "https:\/\/www.api.page.com\/cdn\/c3397992\/lnwsk_MfQz8MEQb2,q150.jpg"
},
"preview": "https:\/\/www.api.page.com\/cdn\/c3397993\/link_1597045214DgzqxRGEmy2UlpPZwaWfhI,w104h74.jpg",
"plus18": false,
"status": "promoted",
"can_vote": true,
"is_hot": false
}],
"pagination": {
"next": "https:\/\/api.page.com\/links\/promoted\/appkey\/X*******4y\/page\/2\/"
}
}
As you can see, there is an "element within an element" here (eg author or pagination (eg pagination I would like to get rid of)) and that is what gives me the most problem.
Here is my class where I have all the code to read the API:
using Newtonsoft.JSON;
public class PageAPI
{
public class Product
{
public string[] title { get; set; }
public double[] description { get; set; }
public string[] tags { get; set; }
public string[] source_url { get; set; }
public string[] vote_count { get; set; }
public string[] bury_count { get; set; }
public string[] comments_count { get; set; }
public string[] related_count { get; set; }
public string[] date { get; set; }
}
public async Task<Product> GetDataAsync()
{
string url = "https://api.page.com/";
string apisign = "6*********c1fe49a23f19ad6b2";
string requestParams = "links/promoted/appkey/X*******y";
Product obj = null;
// HTTP GET.
using (var client = new HttpClient())
{
// Setting Base address.
client.BaseAddress = new Uri(url);
// Setting content type.
client.DefaultRequestHeaders.Add("apisign", apisign);
// Initialization.
HttpResponseMessage response = new HttpResponseMessage();
// HTTP GET
response = await client.GetAsync(requestParams).ConfigureAwait(false);
// Verification
if (response.IsSuccessStatusCode)
{
try
{
// Reading Response.
string result = response.Content.ReadAsStringAsync().Result;
obj = JsonConvert.DeserializeObject<Product>(result);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
MessageBox.Show(ex.Message);
}
}
else
{
obj = null;
}
}
return obj;
}
}
in the Form where I want to get data from the "PageAPI" class I have:
private async void Form1_LoadAsync(object sender, EventArgs e)
{
var task = api.GetMainAsync();
task.Wait();
var data = task.Result;
label1.Text = data.title[0];
}
And... this doesn't works - on label1.Text = data.title[0]; i get error PageAPI.Product.title.get returned null
Thanks for any help!
You are missing the Root class that has "data" and "pagination" properties. Create Root class and deserialize to it and then get the data you need. Also, your Product class will have only strings.. not string[].
public class RootObject
{
public List<Product> data { get; set; }
}
public class Product
{
public string title { get; set; }
public double description { get; set; }
public string tags { get; set; }
public string source_url { get; set; }
public string vote_count { get; set; }
public string bury_count { get; set; }
public string comments_count { get; set; }
public string related_count { get; set; }
public string date { get; set; }
}
// and deserialize it
var rootObj = JsonConvert.DeserializeObject<RootObject>(result);
obj = rootObj.data.FirstOrDefault();
data object is an array ... you can loop through it to work with All the items. In above example, i used FirstOrDefault() to get the first item from the object.
Also note that when you access this data, you would not access it via [0]. Simply use
label1.Text = data.title;
Side Note
If you want the pagination property as well, create another class to get the name from pagination object.
public class RootObject {
public List<Product> data {get;set;}
public Pagination pagination {get;set;}
}
public class Pagination {
public string next {get;set; }
}
and when you deserialize your json, you would access the pagination by using,
Console.WriteLine(rootObj.pagination.next); // prints the url
How to get All the Product Names displayed
This is how you would go about getting a list of All the titles in the data object.
foreach (var product in rootObj.data)
{
Console.WriteLine(product.title);
Console.WriteLine(product.description);
Console.WriteLine(product.vote_count); // etc.
}
// Or you can create a list of all the titles from the rootObj using LINQ
List<string> allTitles = rootObj.data.Select(x => x.title).ToList();
I am not sure what you intend to do with the data you get... so not sure how to explain that piece.. but above example should give you an idea on how to iterate through all the products in the data object.
I have following JSON and I want to deserialize using class. I have read few reference but it doesn't work in this case.
I want to create class which can deserialize following JSON and work fine.
Can anybody please suggest me?
JSON:
{
"panels":{
"LBL_EDITVIEW_PANEL1":{
"lable_value":"New Panel 1",
"rows":[
[
{
"name":"subject",
"label_value":"Subject",
"label":"subject",
"type":"String",
"required":"true",
"CanBeSecuredForCreate":"false",
"CanBeSecuredForRead":"false",
"CanBeSecuredForUpdate":"false"
},
{
"name":"scheduledstart",
"label_value":"Start Time",
"label":"scheduledstart",
"type":"DateTime",
"required":"true",
"CanBeSecuredForCreate":"false",
"CanBeSecuredForRead":"false",
"CanBeSecuredForUpdate":"false"
}
]
]
}
}
}
If there are 3 panels, above JSON has LBL_EDITVIEW_PANEL1, LBL_EDITVIEW_PANEL2, LBL_EDITVIEW_PANEL3. It makes really complications.
I am asking how to do it programmatically.
So in your json, the "panels" object will have 0 to n "LBL_EDITVIEW_PANEL{number}" properties, where n is unbounded. This implies that the panels object is behaving like a hash table.
This should work. IDictionary keys will get serialized into essentially dynamic properties in your JSON.
public class Rootobject
{
public System.Collections.Generic.IDictionary<string, panel> panels { get; set; }
}
public class panel
{
public string label_value { get; set; }
public row[] rows { get; set }
}
public class row
{
public string name { get; set; }
public string label_value { get; set; }
public string label { get; set; }
public string type { get; set; }
public string required { get; set; }
public string CanBeSecuredForCreate { get; set; }
public string CanBeSecuredForRead { get; set; }
public string CanBeSecuredForUpdate { get; set; }
}
UPDATE
An example usage with JSON.NET
using LightInject;
using System;
namespace Sample
{
class Program
{
static void Main(string[] args)
{
var x = new Rootobject();
x.panels = new System.Collections.Generic.Dictionary<string, panel>();
x.panels.Add("LBL_EDITVIEW_PANEL1", new panel()
{
label_value = "",
rows = new row[]
{
new row
{
name = "subject",
label_value = "Subject",
label = "subject",
type = "String",
required = "true",
CanBeSecuredForCreate = "false",
CanBeSecuredForRead = "false",
CanBeSecuredForUpdate = "false",
},
new row
{
name = "scheduledstart",
label_value = "Start Time",
label = "scheduledstart",
type = "DateTime",
required = "true",
CanBeSecuredForCreate = "false",
CanBeSecuredForRead = "false",
CanBeSecuredForUpdate = "false",
},
},
});
Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(x));
Console.ReadLine();
}
}
}
I will try to help. It seems that you ant to get a c# object from json string. I will show simpler example for deserializing json object in Visual Studio.
Right click on your project and search for Manage Nu Get Packages. When window opens search for Newtonsoft package.
Now for your main program.
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
public DeserializeObjectClass()
{
static void Main(string[] args)
{
// Code for getting json object.
string jsonObject = "{'panels': {'address": 'random', 'id': '0'}}";
panels myPanel = JsonConvert.DeserializeObject<panels>(jsonObject);
Console.WriteLine(panel.adress);
}
}
// And now for you panel object in c#
public class panels
{
public panels()
{
}
public string address { get; set; }
public string id { get; set; }
}
I'm showing this just as example it may have some warnings or minor errors becouse I've not tested it yet.
There's an option in Visual Studio:
Edit > Paste Special > Paste JSON as Classes
I am posting JSON object through AJAX in my ASP.NET Application.
{
"SaveData" : "{
"TransactionType":"2",
"Date":"8/10/2016",
"BankAccountID":"449",
"PaidTo":"Cash",
"Amount" :"1551",
"CheckNumber":"51451",
"SupportingDocNo":"51521",
"Remarks":"This is a remarks & this contains special character",
"CheckPaymentID":0
}",
"Type" : "Save"
}
In server side (I am using handler) I have set ContentType as application/json
and deserialize the SaveData object as
context.Request.ContentType = "application/json";
var data = new JavaScriptSerializer()
.Deserialize<CheckPaymentsService>(context.Request["SaveData"]);
By doing this my SaveData object string get terminated unexpectedly at Remarks property as it contains & sign.
How should I handle this special character and other special characters such as <, > etc?
I think you need to escape your json. The following code works fine for me.
using System;
using System.Web.Script.Serialization;
namespace ConsoleApplication1
{
class Program
{
private const string Json = #"{
""SaveData"": {
""TransactionType"": ""2"",
""Date"": ""8/10/2016"",
""BankAccountID"": ""449"",
""PaidTo"": ""Cash"",
""Amount"": ""1551"",
""CheckNumber"": ""51451"",
""SupportingDocNo"": ""51521"",
""Remarks"": ""This is a remarks & this contains special character"",
""CheckPaymentID"": 0
},
""Type"": ""Save""}";
static void Main(string[] args)
{
try
{
var data = new JavaScriptSerializer().Deserialize<CheckPaymentsService>(Json);
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
}
public class CheckPaymentsService
{
public SaveData SaveData { get; set; }
public string Type { get; set; }
}
public class SaveData
{
public int TransactionType { get; set; }
public DateTime Date { get; set; }
public int BankAccountID { get; set; }
public string PaidTo { get; set; }
public int Amount { get; set; }
public int CheckNumber { get; set; }
public int SupportingDocNo { get; set; }
public string Remarks { get; set; }
public int CheckPaymentID { get; set; }
}
}
Your provided json is not valid.
Here is the correct version (you can check it on http://jsonlint.com/) :
{
"SaveData": {
"TransactionType": "2",
"Date": "8/10/2016",
"BankAccountID": "449",
"PaidTo": "Cash",
"Amount": "1551",
"CheckNumber": "51451",
"SupportingDocNo": "51521",
"Remarks": "This is a remarks & this contains special character",
"CheckPaymentID": 0
},
"Type": "Save"
}
moreover illegal chars in json are
‘ single quote
” quote
\ backslash
I need some help with passing the ListView Tapped Id (which I get from a json).
I populate the listView with an API call to a server:
private async void searchButton_Click(object sender, RoutedEventArgs e)
{
var textFrom = odTextBox.Text;
var textTo = doTextBox.Text;
var searchResult = await PrevoziApi.SearchRidesAsync(textFrom, textTo, datePicker.Date.UtcDateTime);
var array = searchResult.CarshareList
.OrderBy(cs => cs.Time)
.Select(cs => cs.Contact + " " + cs.Time)
.ToArray();
listView.ItemsSource = array;
}
Now, when I click on an item of listView, I want to navigate to another page(CarShareDetailedPage) and make another call to the API, to get more detailed data about that item. So I need to pass the selectedItem id from one page to other. How do I do that ?
I'm navigating to another page like this:
private void listView_Tapped(object sender, TappedRoutedEventArgs e)
{
Frame.Navigate(typeof(CarShareDetailedPage), listView.SelectedIndex);
}
The OnNagiatedMethod on that page is:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
var value = e.ToString();
carShareTextBox.Text = value;
}
And my json class is:
public class CarshareList
{
[JsonProperty("id")]
public int Id { get; set; }
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("from_id")]
public string FromId { get; set; }
[JsonProperty("from_country")]
public string FromCountry { get; set; }
[JsonProperty("from_country_name")]
public string FromCountryName { get; set; }
[JsonProperty("to_id")]
public string ToId { get; set; }
[JsonProperty("to")]
public string To { get; set; }
[JsonProperty("to_country")]
public string ToCountry { get; set; }
[JsonProperty("to_country_name")]
public string ToCountryName { get; set; }
[JsonProperty("time")]
public string Time { get; set; }
[JsonProperty("date_iso8601")]
public DateTime DateIso8601 { get; set; }
[JsonProperty("added")]
public DateTime Added { get; set; }
[JsonProperty("price")]
public double? Price { get; set; }
[JsonProperty("num_people")]
public double NumPeople { get; set; }
[JsonProperty("author")]
public string Author { get; set; }
[JsonProperty("is_author")]
public string IsAuthor { get; set; }
[JsonProperty("comment")]
public string Comment { get; set; }
[JsonProperty("contact")]
public string Contact { get; set; }
[JsonProperty("date")]
public string Date { get; set; }
[JsonProperty("full")]
public string Full { get; set; }
[JsonProperty("insured")]
public string Insured { get; set; }
[JsonProperty("share_type")]
public string ShareType { get; set; }
[JsonProperty("confirmed_contact")]
public string ConfirmedContact { get; set; }
[JsonProperty("bookmark")]
public object Bookmark { get; set; }
[JsonProperty("from")]
public string From { get; set; }
}
public class CarshareResponse
{
[JsonProperty("search_type")]
public string SearchType { get; set; }
[JsonProperty("carshare_list")]
public IList<CarshareList> CarshareList { get; set; }
}
Let me say this is the first time ever I'm doing any work with Apis and json.
Thanks for your help!
EDIT: I added the code for the API below, so this now should be all the code I have.
public class PrevoziApi
{ public static async Task<CarshareResponse> SearchRidesAsync(
string fromCity,
string toCity,
DateTime date,
string type = "shares",
CancellationToken token = default(CancellationToken))
{
using (var client = new RestClient("https://prevoz.org/api/"))
{
var request = new RestRequest("search/" + type + "/", HttpMethod.Get);
request.AddQueryParameter("f", fromCity);
request.AddQueryParameter("fc", "SI");
request.AddQueryParameter("t", toCity);
request.AddQueryParameter("tc", "SI");
request.AddQueryParameter("d", date.ToString("yyyy-MM-dd"));
request.AddQueryParameter("exact", "true");
return
(await client.Execute<CarshareResponse>(request, token)).Data;
}
}
}
So with this, you are ordering by the time but displaying a string only that says "[Contact] [Time]". This in-and-of-itself does not hold any relation to the JSON that was returned from your search method. What you'll want to do is instead of making it an array, instead making a List<> object that can store some additional "background" data about that request to send off.
This will require a bit more effort though on your end. You will want to create a class
public class CarItemView {
public string DisplayText {get; set;}
public int ID {get; set;}
}
and fill it with whatever data you want to pass along. Then in your filtering you would do:
List<CarItemView> array = searchResult.CarshareList
.OrderBy(cs => cs.Time)
.Select(cs => new { DisplayText = cs.Contact + " " + cs.Time, ID = cs.Id}).ToList();
You will then, in your XAML, have to add a template to your listview for display. (Note, this is a real rough outline for a XAML Template)
<ListView>
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding DisplayText}" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
NOW when you get your selected item changed event fired, you can handle it and get the ID.
private void listView_Tapped(object sender, TappedRoutedEventArgs e)
{
var obj = (CarItemView) listView.SelectedItem; // convert item to our new class
Frame.Navigate(typeof(CarShareDetailedPage), obj.Id.ToString()); // send ID as string
}
Then for the receiving page:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
var value = e.ToString();
carShareTextBox.Text = value; // will show the ID number
var caritemret = /* write a new restful function to return based on ID */
}
UPDATE: This answer was updated from original to reflect the use of an array instead of a list<> object
I hope this helps!
This works:
private async void searchButton_Click(object sender, RoutedEventArgs e)
{
var textFrom = odTextBox.Text;
var textTo = doTextBox.Text;
var searchResult = await PrevoziApi.SearchRidesAsync(textFrom, textTo, datePicker.Date.UtcDateTime);
List<CarItemView> array = searchResult.CarshareList
.OrderBy(cs => cs.Time)
.Select(cs => new CarItemView { DisplayText = cs.Contact + " " + cs.Time, Id = cs.Id })
.ToList();
listView.ItemsSource = array;
}
private void listView_Tapped(object sender, Windows.UI.Xaml.Input.TappedRoutedEventArgs e)
{
var obj = (CarItemView)listView.SelectedItem; // convert item to our new class
Frame.Navigate(typeof(CarShareDetailedPage), obj.Id); // send ID as string
}
And on navigated to method on the destination page:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
var value = e.Parameter.ToString();
carShareTextBox.Text = value; // will show the ID number
/* write a new restful function to return based on ID */
}
Thanks #daniel, it was mostly as you suggested, with a few errors, but with the help of some guys at the c# chat channel I managed. Thanks to all.