Cannot deserialize the current JSON.Net array C# - c#

I'm pretty new to programming , I still have a lot to learn and I would need a little help please :) !
I saw in other posts the same error but I could not solve anything even with those explanations
The error i get
Newtonsoft.Json.JsonSerializationException: 'Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'JSON_TEST2.Class1+weatherinfo' because the type requires a JSON object (e.g. {"name":"value"}) to deserialize correctly.
To fix this error either change the JSON to a JSON object (e.g. {"name":"value"}) or change the deserialized type to an array or a type that implements a collection interface (e.g. ICollection, IList) like List that can be deserialized from a JSON array. JsonArrayAttribute can also be added to the type to force it to deserialize from a JSON array.
Path 'weather', line 1, position 45.'
I have this class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
namespace JSON_TEST2
{
public class Class1
{
public class coord
{
public double lat { get; set; }
public double lon { get; set; }
}
public class weatherinfo
{
public string[] weather { get; set; }
}
public class WeatherMain
{
public coord coord { get; set; }
public weatherinfo weather { get; set; }
public void display()
{
Console.WriteLine("lon: {0}", this.coord.lon);
Console.WriteLine("lat: {0}", this.coord.lat);
Console.WriteLine("id: {0}", this.weather.weather);
}
}
}
}
I deserialize with this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using System.Net;
namespace JSON_TEST2
{
class Program
{
static void Main()
{
WebClient wc = new WebClient();
var json = wc.DownloadString(#"http://api.openweathermap.org/data/2.5/weather?q=Bucharest,ro&APPID=829b7bfc0558b9e501f43fc6087fca3a");
Console.WriteLine(json);
Class1.WeatherMain vreme = JsonConvert.DeserializeObject <Class1.WeatherMain>(json);
vreme.display();
Console.ReadLine();
}
}
}
This is the JSON I get from the server:
{
"coord":{
"lon":26.1,
"lat":44.44
},
"weather":[
{
"id":804,
"main":"Clouds",
"description":"overcast clouds",
"icon":"04n"
}
],
"base":"stations",
"main":{
"temp":287.64,
"pressure":1012,
"humidity":87,
"temp_min":287.15,
"temp_max":288.15
},
"visibility":8000,
"wind":{
"speed":2.6,
"deg":50
},
"clouds":{
"all":100
},
"dt":1573682313,
"sys":{
"type":1,
"id":6911,
"country":"RO",
"sunrise":1573708189,
"sunset":1573743018
},
"timezone":7200,
"id":683506,
"name":"Bucharest",
"cod":200
}

As described in comments, your classes doesn't match the Json.This is because the weather itself is an array, and not an object.
"weather":[
{
"id":804,
"main":"Clouds",
"description":"overcast clouds",
"icon":"04n"
}
]
You need to alter the weatherinfo and WeatherMain as following.
public class weatherinfo
{
public int id { get; set; }
public string main { get; set; }
public string description { get; set; }
public string icon { get; set; }
}
public class WeatherMain
{
public coord coord { get; set; }
public List<weatherinfo> weather { get; set; }
public void display()
{
Console.WriteLine("lon: {0}", this.coord.lon);
Console.WriteLine("lat: {0}", this.coord.lat);
Console.WriteLine("id: {0}", string.Join(Environment.NewLine,this.weather.Select(c=>$"Weather:{c.main},Description:{c.description}")));
}
}
Demo Code

Related

C# Using Newtonsoft Json to change Property Name of Item in List based upon an Attribute

I am trying to change the name of a property inside of a list by referencing a attribute on the list.
Below is code with an outer class A that holds a list of B. If you notice, on "A" there is [DataMember, ItemName("C")]. In short, I want to use this "ItemName" attribute to rename the "Data" property in B, to "C"
Code:
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
namespace ConsoleApp1
{
public class B
{
[DataMember]
public int Data { get; set; }
}
public class A
{
[DataMember, ItemName("C")]
public List<B> List { get; set; }
}
public class ItemNameAttribute : Attribute
{
public string Name { get; }
public ItemNameAttribute(string name)
{
Name = name;
}
}
class Program
{
static void Main(string[] args)
{
var a = new A();
a.List = new List<B>()
{
new B() { Data = 1 }, new B() { Data = 2 }
};
var json = JsonConvert.SerializeObject(a);
}
}
}
The Expected Json output that I want is
{
"List": [
{
"C": 1
},
{
"C": 2
}
]
}
The current output I have is:
{
"List": [
{
"Data": 1
},
{
"Data": 2
}
]
}
You can use JsonPropertyAttribute to change the names of properties.
This is the source code.
public class B
{
[JsonProperty("C")]
public int Data { get; set; }
}
public class A
{
[JsonProperty("List")]
public List<B> List { get; set; }
}

Error when deserializing JSON object "Unexpected character encountered while parsing value: <. Path '', line 0, position 0."

I am trying to stream a large JSON file and deserialize item by item during the streaming.
I am using for this test https://github.com/ysharplanguage/FastJsonParser/blob/master/JsonTest/TestData/fathers.json.txt.
This is my code:
using Newtonsoft.Json;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using Newtonsoft.Json.Linq;
using System.Threading.Tasks;
namespace AMServices.Controllers
{
public class FathersData
{
public Father[] fathers { get; set; }
}
public class Someone
{
public string name { get; set; }
}
public class Father : Someone
{
public int id { get; set; }
public bool married { get; set; }
// Lists...
public List<Son> sons { get; set; }
// ... or arrays for collections, that's fine:
public Daughter[] daughters { get; set; }
}
public class Child : Someone
{
public int age { get; set; }
}
public class Son : Child
{
}
public class Daughter : Child
{
public string maidenName { get; set; }
}
public class StreamerController : ApiController
{
static readonly JsonSerializer _serializer = new JsonSerializer();
static readonly HttpClient _client = new HttpClient();
[HttpPost]
[Route("streamer/stream")]
public async Task<IHttpActionResult> stream()
{
string apiUrl = "https://github.com/ysharplanguage/FastJsonParser/blob/master/JsonTest/TestData/fathers.json.txt";
using (var stream = await _client.GetStreamAsync(apiUrl).ConfigureAwait(false))
using (var reader = new StreamReader(stream))
using (var json = new JsonTextReader(reader))
{
if (json == null)
StatusCode(HttpStatusCode.InternalServerError);
JsonSerializer serializer = new JsonSerializer();
JObject obj = JObject.Load(json);
// Father f = serializer.Deserialize<Father>(json);
}
return StatusCode(HttpStatusCode.OK);
}
}
}
When i call this WebAPI Controller Method from Postman i get the following error
"ExceptionMessage": "Unexpected character encountered while parsing value: <. Path '', line 0, position 0.",
"ExceptionType": "Newtonsoft.Json.JsonReaderException",
What is wrong with this code?
You are trying to parse an html page.
Try with the raw version :
https://raw.githubusercontent.com/ysharplanguage/FastJsonParser/master/JsonTest/TestData/fathers.json.txt

Deserialize JSON into SQLite Database

My model is GasStation.
using Newtonsoft.Json;
using SQLite;
using System;
using System.Collections.Generic;
using System.Text;
namespace TDEv2.Models
{
public class GasStation
{
[JsonProperty("costcentre")][PrimaryKey]
public string CostCentre { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("id")]
public string Id { get; set; }
}
}
My GasStationQuery contains this:
namespace TDEv2.Models
{
public class GasStationQuery
{
public GasStation[] GasStations { get; set; }
}
}
My JSON Array looks like this:
gasstations: [
{
"id": 01,
"name": "GasStation1",
"costcentre": 123
},
{
"id": 02,
"name": "GasStation2",
"costcentre": 456
}
]
Now I want to deserialize this into my SQLite database:
using SQLite;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using TDEv2.Models;
namespace TDEv2.Data
{
public class GasStationDatabase
{
readonly SQLiteAsyncConnection database;
public GasStationDatabase(string dbPath)
{
database = new SQLiteAsyncConnection(dbPath);
database.CreateTableAsync<GasStation>().Wait();
}
public Task<List<GasStation>> GetItemsAsync()
{
return database.Table<GasStation>().ToListAsync();
}
public Task<GasStation> GetItemAsync(string costCentre)
{
return database.Table<GasStation>().Where(i => i.CostCentre == costCentre).FirstOrDefaultAsync();
}
public Task<int> SaveItemAsync(GasStation gasStation)
{
if (gasStation.CostCentre != null)
{
return database.UpdateAsync(gasStation);
}
else
{
return database.InsertAsync(gasStation);
}
}
}
}
Now I want to do an initial sync to fill my database to work with offline on the devices, but I don't know further steps since I am programming for not that long.
Here's my try to fill the database:
using System.Net;
using TDEv2.Data;
using TDEv2.Models;
namespace TDEv2.Services
{
public class InitialAsyncGasStationDatabase
{
private GasStationDatabase db;
public GasStationQuery InitialAsyncGasStationsToDatabase()
{
string json;
using (WebClient client = new WebClient())
{
json = client.DownloadString($"http://xxx/gasstations.json");
}
foreach (GasStation gasStation in json)
{
db.SaveItemAsync(gasStation);
}
return;
}
}
}
The code doesn't work. I am getting an error in the foreach section with Cannot convert type "char" to "TDEv2.Models.GasStation"
you need to deserialize your json into an object before you can save it to the db
using (WebClient client = new WebClient())
{
json = client.DownloadString($"http://xxx/gasstations.json");
}
// using newtonsoft json.net - use http://json2csharp.com/ to verfiy
// that your C# model class actually matches your json
var data = JsonConvert.DeserializeObject<GasStationQuery>(json);
foreach (GasStation gasStation in data.GasStations)
{
db.SaveItemAsync(gasStation);
}
Probably your source has a list of GasStations, so you can Deserialize your json object into a List of GasStation,
private GasStationDatabase db;
public GasStationQuery InitialAsyncGasStationsToDatabase()
{
string json;
using (WebClient client = new WebClient())
{
json = client.DownloadString($"http://xxx/gasstations.json");
}
var gasStationList = JsonConvert.DeserializeObject<List<GasStation>>(json);
foreach (GasStation gasStation in gasStationList )
{
db.SaveItemAsync(gasStation);
}
return;
}

Deserialize json array to c# list object

I am trying to parse a JSON response from a service to c# observation collection list object. The list object later can be used to showcase on the XAML page.
Here is the response from the service:
[
{
"orderId": 1,
"employeeId": "6364",
"orderTime": 1517583600000,
"orderCost": 90,
"comments": null,
"orderStatus": {
"orderStatusId": 1,
"orderStatusName": "Order Placed"
},
"orderedItems": [
{
"orderItemId": 1,
"orderQuantity": 1,
"orderItemCost": 50
},
{
"orderItemId": 2,
"orderQuantity": 1,
"orderItemCost": 40
}
]
},
{
"orderId": 2,
"employeeId": "6364",
"orderTime": 1517670000000,
"orderCost": 50,
"comments": null,
"orderStatus": {
"orderStatusId": 3,
"orderStatusName": "Order Delivered"
},
"orderedItems": [
{
"orderItemId": 3,
"orderQuantity": 1,
"orderItemCost": 50
}
]
}
]
The following is the model class :
namespace ServiceNew
{
public class OrderStatus
{
public int orderStatusId { get; set; }
public string orderStatusName { get; set; }
}
public class OrderedItem
{
[JsonProperty("orderItemId")]
public int orderItemId { get; set; }
[JsonProperty("orderQuantity")]
public int orderQuantity { get; set; }
[JsonProperty("orderItemCost")]
public int orderItemCost { get; set; }
}
public class Order
{
[JsonProperty("orderId")]
public int orderId { get; set; }
[JsonProperty("employeeId")]
public string employeeId { get; set; }
[JsonProperty("orderTime")]
public object orderTime { get; set; }
[JsonProperty("orderCost")]
public int orderCost { get; set; }
[JsonProperty("comments")]
public object comments { get; set; }
[JsonProperty("orderStatus")]
public OrderStatus orderStatus { get; set; }
[JsonProperty("orderedItems")]
public List<OrderedItem> orderedItems { get; set; }
}
}
The service is like this:
public class OrderService
{
public OrderService()
{
GetJson();
}
public async void GetJson()
{
if (NetworkCheck.IsInternet())
{
var client = new System.Net.Http.HttpClient();
var response = await client.GetAsync("here is thre URL");
string orderJson = await response.Content.ReadAsStringAsync(); //Getting response
Order ObjOrderList = new Order();
if (orderJson != " ")
{
Console.WriteLine("response is"+orderJson);
//exception occurs here all the time , and I need it to be a list
ObjOrderList = JsonConvert.DeserializeObject<Order>(orderJson);
}
Console.WriteLine("obj order list is"+ObjOrderList);
}
}
}
After trying with some changes to the deserialization the JSON array to c#, I was not able to succeed. Now there is an exception saying
Newtonsoft.Json.JsonSerializationException: <Timeout exceeded getting exception details>
And I am stuck at this for a long time, searched over StackOverflow and googled it but no fruitful solution for this.
I need to store the JSON data into a c# object and reproduce the same object in the XAML page as a list.
Thanks in advance!
I am sure that exception is not related to you JSON string but try to remove bin and obj from solution folder and then clean and rebuild solution.
but after resolving that you will get the below exception
Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'namespace.Order' because the type requires a JSON object (e.g. {"name":"value"}) to deserialize correctly.....
Because your JSON string is List of Order so the deserialize would be change to :
List<Order> ObjOrderList = JsonConvert.DeserializeObject<List<Order>>(orderJson);
or in the other side you can also use JavaScriptSerializer like:
Order[] orderList = new JavaScriptSerializer().Deserialize<Order[]>(orderJson);
You are deserializing a List of Orders so you should deserialize like this:
...
List<Order> ObjOrderList;
...
ObjOrderList = JsonConvert.DeserializeObject<List<Order>>(orderJson);
...
Your JSON starts with a [ and ends with a ]. This means that your JSON represents an array of objects. These objects are:
First object
{
"orderId": 1,
"employeeId": "6364",
"orderTime": 1517583600000,
"orderCost": 90,
...
}
Second object
{
"orderId": 2,
"employeeId": "6364",
"orderTime": 1517670000000,
"orderCost": 50,
...
}
In your subconscious you knew it, in fact the name of your deserialized variable is ObjOrderList (highlight List).
So, just deserialize to an array/list of Order.
Example with list
var ObjOrderList = new List<Order>();
if (orderJson != " ")
{
//exception occurs here all the time , and I need it to be a list
ObjOrderList = JsonConvert.DeserializeObject<List<Order>>(orderJson);
}
Example with array
var ObjOrderList = new Order[] { };
if (orderJson != " ")
{
//exception occurs here all the time , and I need it to be a list
ObjOrderList = JsonConvert.DeserializeObject<Order[]>(orderJson);
}
Try this autogenerated code:
// To parse this JSON data, add NuGet 'Newtonsoft.Json' then do:
//
// using yourNameSpace;
//
// var orderResponse = OrderResponse.FromJson(jsonString);
namespace yourNameSpace
{
using System;
using System.Collections.Generic;
using System.Globalization;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
public partial class OrderResponse
{
[JsonProperty("orderId")]
public long OrderId { get; set; }
[JsonProperty("employeeId")]
public string EmployeeId { get; set; }
[JsonProperty("orderTime")]
public long OrderTime { get; set; }
[JsonProperty("orderCost")]
public long OrderCost { get; set; }
[JsonProperty("comments")]
public object Comments { get; set; }
[JsonProperty("orderStatus")]
public OrderStatus OrderStatus { get; set; }
[JsonProperty("orderedItems")]
public List<OrderedItem> OrderedItems { get; set; }
}
public partial class OrderStatus
{
[JsonProperty("orderStatusId")]
public long OrderStatusId { get; set; }
[JsonProperty("orderStatusName")]
public string OrderStatusName { get; set; }
}
public partial class OrderedItem
{
[JsonProperty("orderItemId")]
public long OrderItemId { get; set; }
[JsonProperty("orderQuantity")]
public long OrderQuantity { get; set; }
[JsonProperty("orderItemCost")]
public long OrderItemCost { get; set; }
}
public partial class OrderResponse
{
public static List<OrderResponse> FromJson(string json) => JsonConvert.DeserializeObject<List<OrderResponse>>(json);
}
code was generated using QuickType.io
I discarded the converter and some other extra classes.
You can change the Long type to int if you want.
To use it just call
var orderResponse = OrderResponse.FromJson(jsonString);
pass the response instead of jsonString
In this Code you can DeserializeObject json file:
using (StreamReader r = new StreamReader("D:/Source/ParsijooWeatherApi/ParsijooWeatherApi/cities2.json"))
{
string json = r.ReadToEnd();
List<jsonVariables> items = JsonConvert.DeserializeObject<List<jsonVariables>>(json);
dynamic array = JsonConvert.DeserializeObject(json);
foreach (var item in array)
{
Console.WriteLine("{0} {1}", item.latitude, item.longitude);
}
}
jsonVariables class is:
public class jsonVariables
{
[JsonProperty("latitude")]
public string latitude { get; set; }
[JsonProperty("longitude")]
public string longitude { get; set; }
[JsonProperty("state")]
public string state { get; set; }
}
In this code you access to root directory project:
string _filePath = Path.GetDirectoryName(System.AppDomain.CurrentDomain.BaseDirectory);
then:
StreamReader r = new StreamReader(_filePath + "/cities2.json"))

Error filling an object array from JSON data using DataContractJsonSerializer

I have one problem. I want to read JSON data from my local link and put it in an object class. My problem is that the object[] did not fill with data. Here is my code:
This is the serverdata.cs file with my object inside that I want to fill:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.Serialization;
namespace Διαχείριση
{
class serverdata
{
public προμηθευτέςRow[] Rows;
[DataContract(Name = "ΠρομηθευτέςResult")]
public struct προμηθευτέςRow
{
[DataMember(Name = "Κωδικός")]
public int Κωδικός { get; set; }
[DataMember(Name = "Όνομα")]
public string Όνομα { get; set; }
[DataMember(Name = "Επίθετο")]
public string Επίθετο { get; set; }
[DataMember(Name = "Τηλέφωνο")]
public string Τηλέφωνο { get; set; }
[DataMember(Name = "Διεύθυνση")]
public string Διεύθυνση { get; set; }
[DataMember(Name = "Mail")]
public string Mail { get; set; }
[DataMember(Name = "Προϊόντα")]
public string[] Προϊόντα { get; set; }
}
}
}
Then I have the Form.cs that I want to read the JSON data from my local server:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Runtime.Serialization.Json;
namespace Διαχείριση
{
public partial class Administator_Form : Form
{
serverdata ServerData;
public Administator_Form()
{
ServerData = new serverdata();
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
WebRequest request = WebRequest.Create(string.Format("mylocallink"));
WebResponse response = request.GetResponse();
Stream stream = request.GetResponse().GetResponseStream();
StreamReader sread = new StreamReader(stream);
//string sLine = sread.ReadLine();
//MessageBox.Show(sLine);
DataContractJsonSerializer json = new DataContractJsonSerializer(typeof(List<serverdata.προμηθευτέςRow>));
var result = (List<serverdata.προμηθευτέςRow>)json.ReadObject(stream);
ServerData.Rows = result.ToArray();
}
}
}
Now if I call for example MessageBox.Show(ServerData.Rows[0].Κωδικός.ToString()); I get an exception:
"An unhandled exception of type 'System.IndexOutOfRangeException' occurred in Project.exe
Additional information: Index was outside the bounds of the array."
So my problem is that result didn't fill ServerData.Rows.
Here is the JSON data:
{
"ΠρομηθευτέςResult": [
{
"Mail": "mail1",
"Όνομα": "name1",
"Διεύθυνση": "address1",
"Επ‌​ίθετο": "epitheto1",
"Κωδικός": 1,
"Προϊόντα": [
"subproduct1.1",
"subproduct1.2"
],
"Τηλέ‌​φωνο": "1111111111"
},
{
"Mail": "mail2",
"Όνομα": "name2",
"Διεύθυνση": "address2",
"Επίθε‌​το": "epitheto2",
"Κωδικός": 2,
"Προϊόντα": [
"subproduct2.1",
"subproduct2.2"
],
"Τηλέφων‌​ο": "2222222222"
}
]
}
The issue is that you are trying to deserialize into a list, but in your JSON the row data is not at the root level--it is inside an object. To fix, you need to deserialize to your serverdata class directly. But first, you will need to make a couple of changes to the attributes:
Mark your serverdata class with [DataContract]
Mark the Rows property inside serverdata with [DataMember(Name = "ΠρομηθευτέςResult")]
Mark the προμηθευτέςRow struct with [DataContract]
Your class should look like this:
[DataContract]
class serverdata
{
[DataMember(Name = "ΠρομηθευτέςResult")]
public προμηθευτέςRow[] Rows { get; set; }
[DataContract]
public struct προμηθευτέςRow
{
[DataMember(Name = "Κωδικός")]
public int Κωδικός { get; set; }
[DataMember(Name = "Όνομα")]
public string Όνομα { get; set; }
[DataMember(Name = "Επίθετο")]
public string Επίθετο { get; set; }
[DataMember(Name = "Τηλέφωνο")]
public string Τηλέφωνο { get; set; }
[DataMember(Name = "Διεύθυνση")]
public string Διεύθυνση { get; set; }
[DataMember(Name = "Mail")]
public string Mail { get; set; }
[DataMember(Name = "Προϊόντα")]
public string[] Προϊόντα { get; set; }
}
}
Then, change your code to deserialize to your serverdata class:
DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(serverdata));
ServerData = (serverdata)ser.ReadObject(stream);
You can remove this line as it is no longer needed:
ServerData.Rows = result.ToArray();
After these changes you should find that the Rows array is filled correctly.

Categories