Why is JsonSerializer.Deserializer only partially populating my object? - c#

I have a class defined as follows:
public class NearestLocation
{
public Int32 ID { get; set; }
public String Name { get; set; }
public String TypeID { get; set; }
public String SourceID { get; set; }
public String Code { get; set; }
public Double Latitude;
public Double Longitude;
public Int32? Distance { get; set; }
public String Direction { get; set; }
public String Relative { get; set; }
public DateTime? LastUpdatedOn { get; set; }
}
and a string jsonData returned from an API call that contains the following JSON:
{\"Latitude\":-45.861900329589844,\"Longitude\":170.36294555664063,\"Distance\":13,\"Direction\":\"E\",\"Relative\":\"Helicopters Otago (South)\",\"ID\":413,\"Code\":\"HOLS\",\"Name\":\"Helicopters Otago (South)\",\"TypeID\":\"helipad\",\"SourceID\":\"holcwh\",\"LastUpdatedOn\":\"2022-05-08T23:18:41.987\"}
When I deserialize jsonData into an object as follows:
NearestLocation nearest = JsonSerializer.Deserialize<NearestLocation>(jsonData);
nearest is only partially populated:
Code: "HOLS"
Direction: "E"
Distance: 13
ID: 413
LastUpdatedOn: {8/05/2022 11:18:41 pm}
Latitude: 0
Longitude: 0
Name: "Helicopters Otago (South)"
Relative: "Helicopters Otago (South)"
SourceID: "holcwh"
TypeID: "helipad"
Why are Latitude and Longitude not being populated? I can see the correct values in the JSON, and other values - of types String, Int32 and DateTime - are all being populated correctly. It is only the doubles that are not being populated correctly.
I don't seem to be able to trace into JsonSerializer to see what's going on under the hood - the debugger just steps over the line. I've checked the names in the JSON and in the class definition to make sure they match - which they do - but I am at a loss to understand why this is happening.

Latitude and Longitude are fields. Adding getter and setter in order to convert them to properties.
public class NearestLocation
{
// Other properties
public double Latitude { get; set; }
public double Longitude { get; set; }
}
From the documentation,
By default, fields are ignored. You can include fields.
To include field for serialization/deserialization, you need to apply the [JsonInclude] attribute as mentioned.

Related

Deserialize JSON having keys with CamelCase and snake_case naming in C#

I am receiving a json file via api, that json file will be converted into a class that I cant touch and has around 400 properties. the json is using for the key names CamelCase and in the same json some keys are in the format of snake_case.
I am currently using System.Text.Json but open to change to Newtonsoft.json is needed.
I tried to create a JsonSnakeCaseNamingPolicy class (only converting the property names to snake_case) and used in the JsonSerializerOptions like this:
var deserializeOptions = new JsonSerializerOptions()
{
PropertyNameCaseInsensitive = true,
PropertyNamingPolicy = new JsonSnakeCaseNamingPolicy()
};
var flexImport = JsonSerializer.Deserialize<List<FlexImport>>(input.MappedObjectJson, deserializeOptions);
But then the properties in CamelCase don't get populated. Any idea on how to achieve this situation?
This the json sample:
[{\"BatchId\":123,\"Title_Id\":123,\"CurrentNumber\":\"aa705128\",\"address\":\"122 BLACKSGATE EN\",\"curr_interest_rate\":4},{\"BatchId\":2,\"Title_Id\":1,\"CurrentNumber\":\"27705128\",\"address\":\"90 ARMA DR\",\"curr_interest_rate\":5},{\"BatchId\":2,\"Title_Id\":2,\"CurrentNumber\":\"30877674\",\"address\":\"6485 N SIN CIR\",\"curr_interest_rate\":4}]"
And here is part of the destination class:
public class FlexImport
{
public long BatchId { get; set; }
public long TitleId { get; set; }
public string CurrentNumber { get; set; }
public string Address { get; set; }
public decimal? CurrInterestRate { get; set; }
}
Use JSON attributes
public class FlexImport
{
public long BatchId { get; set; }
[JsonPropertyName("Title_Id")]
public long TitleId { get; set; }
public string CurrentNumber { get; set; }
[JsonPropertyName("address")]
public string Address { get; set; }
[JsonPropertyName("curr_interest_rate")]
public decimal? CurrInterestRate { get; set; }
}
Etc. Adjust as needed.

Convert JSON string to object C#

I have JSON string results as follows.
In this response Sometimes sizeKey and sizeName properties are returned as a string. But sometimes both properties are returns inside an array as follows
I am using following code to convert it to object
var assets = jObject["assets"].Children().ToList();
foreach (var item in assets)
{
decorationAssets.Add(item.ToObject<AEDecorationAssets>());
}
And my AEDecorationAssets class is as follows.
public class AEDecorationAssets
{
public string Id { get; set; }
public string Url { get; set; }
public string[] Colors { get; set; }
public string FontKey { get; set; }
public string SizeKey { get; set; }
public string ViewKey { get; set; }
public string FontName { get; set; }
public int Rotation { get; set; }
public string SizeName { get; set; }
public string TextValue { get; set; }
public string EntityType { get; set; }
public string LocationCode { get; set; }
public string LocationName { get; set; }
public string TextEffectKey { get; set; }
public string TextEffectName { get; set; }
public string DecorationMethod { get; set; }
public string NumDecorationColors { get; set; }
}
At the time when "sizeKey" is an array, the above code gives an error. How can I resolve this issue? Is there any JSON property we can use to resolve it?
One way you can do it is by making your SizeKey type an object (i.e. public object SizeKey { get; set; }), then you can switch/case on item.ToObject<AEDecorationAssets>().SizeKey.GetType() to figure out how to handle it (i.e. if String do this, if JArray do that), etc.
If a JSON type is sometime an array, and sometimes a string, you can't really map it simply to a .NET type, as there is none that supports this behavior.
So first you need a datatype that can store this, like and string[] or List<string>.
It could be that JsonConvert will solve this automatically, but otherwise you'll need to write a custom ContractResolver or JsonConverter. Here you can detect if the source property is a string or array. If it's an array, you can use the default deserialization. If it is a string, you need to convert it to an array with a single value.
Simply get json result for which you want to create c# object and then you can valid json response from https://jsonlint.com/ and then you can create c# object of any type json response which you want through http://json2csharp.com. And after get c# object of your json response you only need to deserialization of your json response to c# object which you have created. which will return you expected result.

Deserialize multiple JSON records in C# [duplicate]

This question already has an answer here:
Deserializing JSON into an object
(1 answer)
Closed 5 years ago.
I have the following string of Json records:
{
"records":[
{
"PK":"1_1_8",
"ID":"8",
"DeviceID":"1",
"RootID":"1",
"CustName":"test1",
"CustSurname":"test2",
"Address":"Nisou 1",
"City":"",
"ZipCode":"",
"PhoneNumber":"45646",
"HomePhoneNumber":"",
"Email":"",
"Notes":"",
"Owner":"1",
"LanguageID":"1",
"LanguagePK":"",
"DeletedFlag":"false",
"created":"2017-10-25 10:15:00",
"modified":"2017-10-25 09:35:43"
},
{
"PK":"1_1_33",
"ID":"33",
"DeviceID":"1",
"RootID":"1",
"CustName":"",
"CustSurname":"",
"Address":"",
"City":"",
"ZipCode":"",
"PhoneNumber":"",
"HomePhoneNumber":"",
"Email":"",
"Notes":"",
"Owner":null,
"LanguageID":"0",
"LanguagePK":"",
"DeletedFlag":"true",
"created":"2017-10-25 10:13:54",
"modified":"2017-10-25 10:13:54"
},
{
"PK":"1_1_16",
"ID":"16",
"DeviceID":"1",
"RootID":"1",
"CustName":"Theodosis",
"CustSurname":"",
"Address":"Dali",
"City":"Nicosia",
"ZipCode":"2540",
"PhoneNumber":"45645",
"HomePhoneNumber":"99123456",
"Email":"theodosis#gmail.com",
"Notes":"",
"Owner":"",
"LanguageID":"1",
"LanguagePK":"",
"DeletedFlag":"false",
"created":"2017-10-25 09:36:22",
"modified":"2017-10-25 09:36:22"
}
]
}
I am using Xamarin PCL in C# trying to parse this string into a list of objects.
I have a Customer class:
public class Customer
{
[PrimaryKey]
public string PK { get; set; }
public int DeviceID { get; set; }
public int ID { get; set; }
public string RootID{ get; set; }
public string CustName { get; set; }
public string CustSurname { get; set; }
public string Address { get; set; }
public string City { get; set; }
public string ZipCode { get; set; }
public string PhoneNumber { get; set; }
public string HomePhoneNumber { get; set; }
public string Email { get; set; }
public string Notes { get; set; }
public bool Owner { get; set; }
public int LanguageID { get; set; }
public string LanguagePK { get; set; }
public bool DeletedFlag { get; set; }
public DateTime created { get; set; }
public DateTime modified { get; set; }
}
I also tried out having a container class with a list of Customer objects.
public class DataContainer
{
public List<Customer> customers { get; set; }
}
I have seen quite a few of examples online on how to parse this into a list or any workable type but nothing seems to be working for me.
I have tried the following (JsonResults holds the string of Json records):
var observation = JsonConvert.DeserializeObject<DataContainer>(JsonResults);
From other posts, I am not able to access JavaScriptSerializer class from my code, perhaps because of the Xamarin PCL Framework I am using.
Any ideas would be very welcome, as I said I do not mind the format I parse the string into, as long as it's workable.
Thank you.
You would have to make the following changes to your code to make this work.
First and most importantly, you don't have a property customers, you have records, so either rename it
public class DataContainer {
public List<Customer> records { get; set; }
}
or add a JsonProperty attribute
[JsonProperty(PropertyName = "records")]
Secondly, your Owner is a bool in C# and a nullable int (int?) in Json. So either change it in your C# class
public int? Owner { get; set; }
or write a converter to do that (e.g. like here)
[JsonConverter(typeof(NullableIntToBooleanConverter))]
public bool Owner { get; set; }
Here is a working .NetFiddle
The JSON string you provided is a JSON object, which contains a single property called records. records property is a List<Customer>. You can not deserialize the given string directly into DataContainer class that you provided because the property names do not match.
In the Class that your provided it is called customers
public class DataContainer {
public List<Customer> customers { get; set; } //records
}
Or please have a look at the attribute for a bit of advanced mapping
[JsonProperty]
JSON you provided is of the form:
{"records":[{Customer},{Customer},{Customer}]}
But Owner property is "1", null or "". Therefore I would suggest redefining Owner as int? (nullable)
Your string shows one object with a property named records that contains a list of other objects. Your code is trying to deserialize this into an object that doesn't have such a property.
Furthermore, the string contains objects with a property Owner that may be missing or have a numeric value. It's definitely not a bool.
You'll have to change Owner to :
public int? Owner { get; set; }
To deserialize the string, you need an object with a records property:
public class DataContainer
{
public Customer[] records { get; set; }
}
var data=JsonConvert.DeserializeObject<DataContainer>(json);
Debug.Assert(data.records.Length == 3);

JSON deserializing

I am trying to deserializing JSON file which looks like:
{"dataset":{"id":14686248,
"dataset_code":"EURUSD",
"database_code":"ECB",
"name":"EUR vs USD Foreign Exchange Reference Rate",
"description":"Euro (EUR) vs. US Dollar (USD) reference exchange rate. Foreign exchange reference rates are published by the European Central Bank. Reference rates are usually updated by 3:00pm CET, based on a regular daily concertation procedure between various central banks across Europe and around the world. This procedure normally takes place at 2:15pm CET. Reference rates are mid-market rates, calculated as averages of the buying and selling rate; they do not necessarily reflect actual transaction rates. Euro foreign exchange reference rates are always quoted using the 'certain' method (i.e EUR 1 = X foreign currency units, where X is the published reference rate).",
"refreshed_at":"2016-12-01T23:16:13.829Z",
"newest_available_date":"2016-12-01",
"oldest_available_date":"1999-01-04",
"column_names":["Date","Value"],
"frequency":"daily",
"type":"TimeSeries",
"premium":false,
"limit":null,
"transform":null,
"column_index":null,
"start_date":"1999-01-04",
"end_date":"2016-12-01",
"data":[["2016-12-01",1.0627]
,["2016-11-30",1.0635],
...
}}
Here what i have done:
class request
{
[JsonProperty("dataset")]
public dataset dataset { get; set; }
}
class dataset
{
public int id { get; set; }
public string dataset_code { get; set; }
public string database_code { get; set; }
public string name { get; set; }
public string description { get; set; }
public string refreshed_at { get; set; }
public DateTime newest_available_date { get; set; }
public string[] column_names { get; set; }
public string frequency { get; set; }
public string type { get; set; }
public DateTime oldest_available_date { get; set; }
public bool premium { get; set; }
public string column_index { get; set; }
public DateTime start_date { get; set; }
public DateTime end_date { get; set; }
[JsonProperty("data")]
public List<innerdata> data { get; set; }
}
class Data
{
public List<innerdata> data { get; set; }
}
class innerdata
{
public DateTime date { get; set; }
public double rate { get; set; }
static void Main(string[] args)
{
try
{
using (var client = new HttpClient())
{
string result = client.GetStringAsync(MakeQuery()).Result;
var weatherData = JsonConvert.DeserializeObject<request> (result);
}
}
catch (Exception ex)
{
Console.WriteLine("An error occured: " + ex.Message);
}
}
And it ends with an error :
Cannot deserialize the current JSON array (e.g. [1,2,3]) into type
'ApiTest.innerdata' 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
'dataset.data[0]', line 1, position 1122.
Try this:
[JsonProperty( "data" )]
public List<List<object>> data { get; set; }
In your json in data, you have an array which has an array inside it. The array inside has a datetime at index 0 and a number with decimal at index 1. In C# you cannot have an array with 2 types (date and number). You can use List<object> instead.
It's to do with data
"data":[["2016-12-01",1.0627] ,["2016-11-30",1.0635],
As it stands this is an array of array's without a key pair. Should be more like the below
"data":[{"date": "2016-12-01","rate":1.0627}
,{"date":"2016-11-30","rate":1.0635}]

Convert meters to kilometers and format the value in Viewmodel

I have the Viewmodel:
public class PartnerSearchResultVM
{
public int Id { get; set; }
public string Name { get; set; }
public string Latitude { get; set; }
public string Longitude { get; set; }
public double Distance { get; set; }
public string Classification { get; set; }
}
I get the distance in meters from the database like this: 2354,58764478263 m
I would like to present 2.35 km
How change the Viewmodel to make the convertion there (if it's the best place to do it)
I'd add a read-only property to your model.
public double Kilometers { get { return this.Distance / 1000; } }
If you want a formatted string back I'd create a second readonly property.
public string KilometerDisplay {
get {
return String.Format("{0:0.00}km", this.Kilometers);
}
}
Although, depending on your use case, a generalized format function might be appropriate. Perhaps as an extension method:
[Extension]
public string FormatDistance(this double distance) {
return distance.FormatDistance("");
}
[Extension]
public string FormatDistance(this double distance, string unitString) {
return return String.Format("{0:0.00}{1}", distance, unitString);
}
// for meters: result.Distance.FormatDistance("m");
// for kilometers: result.Kilometers.FormatDistance("km");
Then add some XML documentation to the Distance property explaining that it is in meters.

Categories