Using the method JsonConvert.DeserializeObject returns the default values for all properties.
var current = JsonConvert.DeserializeObject<Current>(myJson);
{
"location": {
"name": "London"
},
"current": {
"temp_c": 5.0,
"cloud": 50
}
}
public class Current
{
public double Temp_c { get; set; }
public double Cloud { get; set; }
}
The expected current object should have the values: 50 for Cloud, and 5.0 for Temp_c, but returns the default values for all properties.
You need to define a class model like json object
and then deserialize to it
public class YourModel {
//create location class that has Name property
public Location Location { get; set; }
//create current class that has Temp_c and Cloud property
public Current Current { get; set; }
}
and then
var data = JsonConvert.DeserializeObject<YourModel>(myJson);
and get the current value from data object
var current = data.Current;
your 'Current' class is far of been like the JSON you post.
You need to convert the JSON string to a C# class. You can use QuickType to convert it (Newtonsoft compatible).
Note: I am using System.Text.Json.Serialization but the class model should be equal, just change:
[JsonPropertyName("temp_c")] // .Net serializer (I prefer this)
to
[JsonProperty("temp_c")] // Newtonsoft.Json serializer
(replace "temp_c" for every name)
Here is the class model (a complete console application) you need:
using System;
using System.Text.Json;
using System.Text.Json.Serialization;
#nullable disable
namespace test
{
public class Weather
{
[JsonPropertyName("location")]
public Location Location { get; set; }
[JsonPropertyName("current")]
public Current Current { get; set; }
}
public class Location
{
[JsonPropertyName("name")]
public string Name { get; set; }
}
public class Current
{
[JsonPropertyName("temp_c")]
public double TempC { get; set; }
[JsonPropertyName("cloud")]
public int Cloud { get; set; }
}
class Program
{
static void Main(string[] args)
{
string json = "{\"location\": { \"name\": \"London\" }, \"current\": { \"temp_c\": 5.0, \"cloud\": 50 }}";
Weather myWeather = JsonSerializer.Deserialize<Weather>(json);
Console.WriteLine("Location: {0} - Temp: {1:F}", myWeather.Location.Name, myWeather.Current.TempC);
}
}
}
Now the Deserializer will work OK.
Related
All,
Edit: Firstly thanks for everyone's help. Secondly I'm new to Stack Overflow so apologises if I've added this edit incorrectly.
Following the commments and replies I've updated my class structure to:
services class:
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.Json;
namespace RTT_API
{
class services
{
public List<service> service = new List<service>();
public services()
{
}
}
}
Service class:
using System;
using System.Collections.Generic;
using System.Text;
namespace RTT_API
{
class service
{
public string atocCode{get; set;}
public service()
{
}
}
}
Unfortunately I'm still getting the same error. I think I still haven't quite matched my class structure to the JSON structure? Unfortunately I'm not sure where my mistake is. If it helps to highlight my mistake using a comparison then the following works:
Location class
using System;
using System.Collections.Generic;
using System.Text;
namespace RTT_API
{
class location
{
public string name { get; set; }
public string crs { get; set; }
public location()
{
}
}
}
Location deserilisation command and test output:
location locations = JsonSerializer.Deserialize<location>(channelResponse.RootElement.GetProperty("location").GetRawText());
MessageBox.Show(locations.crs);
Original question:
My JSON is as follows:
{
"location": {
"name": "Bournemouth",
"crs": "BMH",
"tiploc": "BOMO"
},
"filter": null,
"services": [
{
"locationDetail": {
"realtimeActivated": true,
"tiploc": "BOMO",
"crs": "BMH",
"description": "Bournemouth",
"wttBookedArrival": "011630",
"wttBookedDeparture": "011830",
"gbttBookedArrival": "0117",
"gbttBookedDeparture": "0118",
"origin": [
{
"tiploc": "WATRLMN",
"description": "London Waterloo",
"workingTime": "230500",
"publicTime": "2305"
}
],
"destination": [
{
"tiploc": "POOLE",
"description": "Poole",
"workingTime": "013000",
"publicTime": "0130"
}
],
"isCall": true,
"isPublicCall": true,
"realtimeArrival": "0114",
"realtimeArrivalActual": false,
"realtimeDeparture": "0118",
"realtimeDepartureActual": false,
"platform": "3",
"platformConfirmed": false,
"platformChanged": false,
"displayAs": "CALL"
},
"serviceUid": "W90091",
"runDate": "2013-06-11",
"trainIdentity": "1B77",
"runningIdentity": "1B77",
"atocCode": "SW",
"atocName": "South West Trains",
"serviceType": "train",
"isPassenger": true
}
]
}
My class structure is as follows:
servicelist class:
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.Json;
namespace RTT_API
{
class servicelist
{
public List<services> service = new List<services>();
public servicelist()
{
}
}
}
services class:
using System;
using System.Collections.Generic;
using System.Text;
namespace RTT_API
{
class services
{
public int serviceUid;
public services()
{
}
}
}
For deserialisation I have tried:
services servicelist = JsonSerializer.Deserialize<services>(channelResponse.RootElement.GetProperty("services").GetRawText());
and
servicelist servicelist = JsonSerializer.Deserialize<servicelist>(channelResponse.RootElement.GetProperty("services").GetRawText());;
In both cases I get 'System.Text.Json.JsonException'
I think there is a mismatch betwee the class structure and the JSON but I can't work what the problem is? It's the first time I've tried to desarialise an array.
Thanks
using System;
using System.Collections.Generic;
using System.Text;
namespace RTT_API
{
class location
{
public string name { get; set; }
public string crs { get; set; }
public location()
{
}
}
}
You can generate exact C# classes according to your JSON using tools for exactly that purpose. I used https://json2csharp.com/ , another is https://jsonutils.com/ - these are web services and don't require installation on computer, another option is generating classes through Visual Studio (with Web Essentials installed), there you would use Edit - Paste special - paste JSON as class.
Once you have the valid classes (I pasted generated classes below) you can deserialize entire Root object and then access any part of it, including services part:
// jsonInputText holds entire JSON string you posted
Root root = JsonSerializer.Deserialize<Root>(jsonInputText);
List<Service> serviceList = root.services;
Generated classes:
public class Location
{
public string name { get; set; }
public string crs { get; set; }
public string tiploc { get; set; }
}
public class Origin
{
public string tiploc { get; set; }
public string description { get; set; }
public string workingTime { get; set; }
public string publicTime { get; set; }
}
public class Destination
{
public string tiploc { get; set; }
public string description { get; set; }
public string workingTime { get; set; }
public string publicTime { get; set; }
}
public class LocationDetail
{
public bool realtimeActivated { get; set; }
public string tiploc { get; set; }
public string crs { get; set; }
public string description { get; set; }
public string wttBookedArrival { get; set; }
public string wttBookedDeparture { get; set; }
public string gbttBookedArrival { get; set; }
public string gbttBookedDeparture { get; set; }
public List<Origin> origin { get; set; }
public List<Destination> destination { get; set; }
public bool isCall { get; set; }
public bool isPublicCall { get; set; }
public string realtimeArrival { get; set; }
public bool realtimeArrivalActual { get; set; }
public string realtimeDeparture { get; set; }
public bool realtimeDepartureActual { get; set; }
public string platform { get; set; }
public bool platformConfirmed { get; set; }
public bool platformChanged { get; set; }
public string displayAs { get; set; }
}
public class Service
{
public LocationDetail locationDetail { get; set; }
public string serviceUid { get; set; }
public string runDate { get; set; }
public string trainIdentity { get; set; }
public string runningIdentity { get; set; }
public string atocCode { get; set; }
public string atocName { get; set; }
public string serviceType { get; set; }
public bool isPassenger { get; set; }
}
public class Root
{
public Location location { get; set; }
public object filter { get; set; }
public List<Service> services { get; set; }
}
If you need to deserialize only just a part of your json then you can use the JObject and JToken helper classes for that.
var json = File.ReadAllText("Sample.json");
JObject topLevelObject = JObject.Parse(json);
JToken servicesToken = topLevelObject["services"];
var services = servicesToken.ToObject<List<Service>>();
The topLevelObject contains the whole json in a semi-parsed format.
You can use the indexer operator to retrieve an object / array by using one of the top level keys.
On a JToken you can call the ToObject<T> to deserialize the data into a custom data class.
In order to be able to parse your json I had to adjust the services type because the W90091 as serviceUid can't be parsed as int. So here is my Service class definition:
public class Service
{
public string ServiceUid;
}
One thing to note here is that casing does not matter in this case so please use CamelCasing in your domain models as you would normally do in C#.
Thanks for everyone's help.
Firstly I had to make a few changes to the class names as they didn't match the JSON. I also had to change the syntax of two commands which I've detailed below:
I changed the definition of the list of objects from:
public List<services> service = new List<services>();
to:
public List<service> destination { get; set; };
and deserilisation command from:
services servicelist = JsonSerializer.Deserialize<services>(channelResponse.RootElement.GetProperty("services").GetRawText());
to
var servicelist = JsonSerializer.Deserialize<List<service>>(channelResponse.RootElement.GetProperty("services").GetRawText());
The change from services to var might not be the best solution. I think it's the first change, and matching the class names to the JSON, that fundamentally fixed the issue.
I need a little assistance in obtaining values from a JSON object in C#. Here is the code and the output. I am trying to retrieve value of ScoreRepresentation from both the objects. The obtained values in this case would be BR400L and null as per the below output.
Can anyone please assist? Newbie in C# :) Thanks in advance
using System;
using Microsoft.VisualBasic;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Test
{
class Program
{
static void Main(string[] args)
{
var json = "{\"Results\":[{\"RequestIdentifier\":\"Lexile\",\"ValueType\":\"INTEGER\",\"Scores\":[{\"lexile\":{\"ScoreValue\":-400,\"ScaledScore\":-400,\"ScoreRepresentation\":\"BR400L\"}}]},{\"RequestIdentifier\":\"UnifiedScaleScore\",\"ValueType\":\"INTEGER\",\"Scores\":[{\"unifiedScaleScore\":{\"ScoreValue\":610,\"ScaledScore\":610,\"ScoreRepresentation\":null}}]}]}";
var deserialized = JsonConvert.DeserializeObject(json);
Console.WriteLine(deserialized);
}
}
}
Output:
{
"Results": [
{
"RequestIdentifier": "Lexile",
"ValueType": "INTEGER",
"Scores": [
{
"lexile": {
"ScoreValue": -400,
"ScaledScore": -400,
"ScoreRepresentation": "BR400L"
}
}
]
},
{
"RequestIdentifier": "UnifiedScaleScore",
"ValueType": "INTEGER",
"Scores": [
{
"unifiedScaleScore": {
"ScoreValue": 610,
"ScaledScore": 610,
"ScoreRepresentation": null
}
}
]
}
]
}
I like to go the "Model" route. You create models of your data, then you can easily deserialize to them. Sometimes when I am feeling lazy, I will use this site to do my work for me.
So, for your specific example, it gives back these models:
public class Lexile {
public int ScoreValue { get; set; }
public int ScaledScore { get; set; }
public string ScoreRepresentation { get; set; }
}
public class UnifiedScaleScore {
public int ScoreValue { get; set; }
public int ScaledScore { get; set; }
public object ScoreRepresentation { get; set; }
}
public class Score {
public Lexile lexile { get; set; }
public UnifiedScaleScore unifiedScaleScore { get; set; }
}
public class Result {
public string RequestIdentifier { get; set; }
public string ValueType { get; set; }
public List<Score> Scores { get; set; }
}
public class Root {
public List<Result> Results { get; set; }
}
Then, you can simply deserialize to Root by doing this:
var deserialized = JsonConvert.DeserializeObject<Root>(json);
Keep in mind that if your JSON is not perfect, you will find some inconsistencies with the output. You may have to massage your models a bit to fix those issues. You can't just assume that site gives you 100% accurate data.
But, if it's good enough, you can now get at every property you'd ever need to without having to putz around with dynamics or JToken.
For example:
foreach(var r in deserialized.Results)
{
foreach(var s in r.Scores)
{
Console.Write(s.unifiedScaleScore.ScoreRepresentation);
}
}
I’ve got a base class (which is used a base for a User class):
public abstract class UserB2C
{
…
public List<SignInName> SignInNames { get; set; }
…
}
public class SignInName
{
string Type { get; set; }
string Value { get; set; }
}
And some JSON which includes:
\"signInNames\":[{\"type\":\"emailAddress\",\"value\":\"user#yahoo.co.uk\"}],
which is passed to:
JsonConvert.DeserializeObject<User>(json);
But the object created (deserialised) has:
"signInNames": [
{}
],
Any ideas why the field doesn’t get populated?
There is no error generated.
All other (simple) values get populated ok.
I've tried changing the case of Type and Value to match the JSON string,
and also tried explicitly creating the List<SignInName> when the object is created, but to no avail.
Properties of SignInName class should be declared as public in order to be deserialized with values.
public class SignInName
{
public string Type { get; set; }
public string Value { get; set; }
}
UPDATE
Here is a Minimal, Complete, and Verifiable example:
using Newtonsoft.Json;
using System.Collections.Generic;
class Program
{
static void Main(string[] args)
{
var json =
"{\"signInNames\":[{\"type\":\"emailAddress\",\"value\":\"user#example.com\"}]}";
var user = JsonConvert.DeserializeObject<User>(json);
System.Console.WriteLine(JsonConvert.SerializeObject(user));
}
}
public abstract class UserB2C
{
public List<SignInName> SignInNames { get; set; }
}
public class User : UserB2C { }
public class SignInName
{
string Type { get; set; }
string Value { get; set; }
}
Output is {"SignInNames":[{}]}
If we make SignInName class properies public the output will be:
{"SignInNames":[{"Type":"emailAddress","Value":"user#example.com"}]}
I'm using the Newtonsoft JSON parser in C#. The JSON seems to be formatted correctly but I'm getting a read error that doesn't make sense. The JSON should deserialize and load into the class instance automatically.
Class:
class FilterMatrix {
public int ID { get; set; }
public int ParentID { get; set; }
}
Deserializing code:
string fileName = #"C:\Users\accounts.json";
FilterMatrix kernel = JsonConvert.DeserializeObject<FilterMatrix>(File.ReadAllText(fileName));
JSON file contents:
{"Features":[{"ID":0,"ParentID":0},{"ID":0,"ParentID":0}]}
Error:
Newtonsoft.Json.JsonReaderException: 'Unexpected character encountered while parsing value: {. Path 'Features', line 1, position 14.'
Well, at least the structure of the JSON needs to match your class hierarchy. Working example:
class Program
{
static void Main(string[] args)
{
var root = JsonConvert.DeserializeObject<Root>(File.ReadAllText("file.json"));
}
}
public class Root
{
public List<FilterMatrix> Features { get; set; }
}
public class FilterMatrix
{
public int ID { get; set; }
public int ParentID { get; set; }
}
Thanks, Gene.
I basically came up with this as I saw your post. It never donned on me to have multiple classes within a class. I guess I assumed an array of classes would be automatically made :-/
JSON script:
{"Features":[{"ID":0,"ParentID":0},{"ID":0,"ParentID":0}]}
Deserialization:
kernel = JsonConvert.DeserializeObject<FilterMatrix>(File.ReadAllText(fileName));
My classes:
class FilterMatrix {
private List<Feature> features = new List<Feature>();
public List<Feature> FeaturesList
{
get { return features; }
set { features = value; }
}
}
class Feature {
public int ID { get; set; }
public int ParentID { get; set; }
}
I access elements by their index:
kernel.FeaturesList[0].ID
I am consuming an API that returns the following JSON:
[
{
"product": {
"id": 2,
"name": "Auto"
}
}
]
So, I am trying to deserialize this in C# object wihout success.
I'd tried a lot of other's stackoverflow solutions.
Here are my attempt:
public class DomainMessageResponse : BaseResponseMessage
{
public Example data { get; set; }
}
public class Example
{
[JsonProperty("product")]
public Product product { get; set; }
}
public class Product
{
[JsonProperty("id")]
public int id { get; set; }
[JsonProperty("name")]
public string name { get; set; }
}
The problem is that the JSON is beginning with [] and our generic method (that I use from an internal framework) was not able to due with it. I'm getting the following exception:
Cannot deserialize the current JSON array (e.g. [1,2,3]) into type....
Thanks #EZI and #eocron for valid solution's.
You should deserialize to array/list. Below code should work...
var list = JsonConvert.DeserializeObject<List<Item>>(json);
public class Product
{
public int id { get; set; }
public string name { get; set; }
}
public class Item
{
public Product product { get; set; }
}
There is two solutions to your problem, considering the way you want to use your object.
First one is to simply create DTO with same fields. Used when you need full control:
using System.Collections.Generic;
using System.Runtime.Serialization;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
namespace ConsoleTest
{
class Program
{
[DataContract]
public class Example
{
[DataMember]
public Product Product { get; set; }
}
[DataContract]
public class Product
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string Name { get; set; }
}
static void Main(string[] args)
{
var json = #"
[
{
""product"": {
""id"": 2,
""name"": ""Auto""
}
}
]";
var obj = JsonConvert.DeserializeObject<List<Example>>(json,
new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
});
}
}
}
The second one used when you want a few fields from json and don't care much about everything else, and uses dynamic type. Easy to code, easy to use, looks pretty good, but not very safe:
using System.Collections.Generic;
using Newtonsoft.Json;
namespace ConsoleTest
{
class Program
{
static void Main(string[] args)
{
var json = #"
[
{
""product"": {
""id"": 2,
""name"": ""Auto""
}
}
]";
dynamic list = JsonConvert.DeserializeObject<List<dynamic>>(json);
var id = (int)list[0].product.id;
}
}
}