0

I get the following json string format from an API:

{
 "Items":[
 {
 "Item":{
 "Codes":{},
 "Date":1523539700000,
 "Name":"Item1",
 "Price":"15"
 }
 },
 {
 "Item":{
 "Codes":{
 "productcode":"a",
 "departmentcode":"b",
 "storecode":"c"
 },
 "Date":1523537700000,
 "Name":"Item2",
 "Price":"20"
 }
 },
 {
 "Item":{
 "Codes":{
 "productcode":"a",
 "departmentcode":"b",
 "storecode":"c"
 },
 "date":1523539700000,
 "name":"Item3",
 "price":"30"
 }
 }
 ]
}

I am not interested in the Codes element and then created the following class:

public class Item
 {
 [JsonConverter(typeof(ConvertItemDateTime))]
 [JsonProperty(PropertyName = "dateReceived")]
 public DateTime DateReceived { get; set; }
 [JsonProperty(PropertyName = "name")]
 public string Name{ get; set; }
 [JsonProperty(PropertyName = "price")]
 public double Price{ get; set; }
 public IList<Items> itemListResults { get; set; } //For view
 public int productid; // Added for view
 }

I then try an parse it...

JObject jsondata = JObject.Parse(responseToString(response))
var values = json.GetValue("Items");

...which by this point I can see that variable 'values' still contains each value (Date, Name, Price) inside each item. Then I try and deserialize it...

IList<Items> itemList = new List<Items>();
itemList = JsonConvert.DeserializeObject<IList<Items>>(values.ToString());

When I debug from this point onward I can see a list with the exact number of items I am expecting but all the values (Date, Name, Price) are null. The Date value inside the json will change (from the API side). Sometimes it will be a long and sometimes a string date format containing a "[GMT]".

My ConvertItemDateTime method is as follow:

public class ConvertItemDateTime : JsonConverter
 {
 private static readonly DateTime UnixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
 public override bool CanConvert(Type objectType)
 {
 Console.WriteLine(objectType);
 return true;
 }
 public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
 {
 Console.WriteLine(value.GetType());
 long ticks;
 if (value is DateTime)
 {
 var dateTime = (DateTime)value;
 ticks = (long)(dateTime.ToUniversalTime() - UnixEpoch).TotalMilliseconds;
 }
 else if (value is DateTimeOffset)
 {
 var dateTimeOffset = (DateTimeOffset)value;
 ticks = (long)(dateTimeOffset.ToUniversalTime() - UnixEpoch).TotalMilliseconds;
 }
 else
 {
 throw new JsonSerializationException("Expected date object value.");
 }
 if (ticks < 0)
 {
 throw new JsonSerializationException("Cannot convert date value that is before Unix epoch of 00:00:00 UTC on 1 January 1970.");
 }
 writer.WriteValue(ticks);
 }
 public override bool CanRead
 {
 get { return true; }
 }
 public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
 {
 long ticks;
 if (reader.TokenType == JsonToken.Integer)
 {
 ticks = (long)reader.Value;
 }
 else if (reader.TokenType == JsonToken.String)
 {
 var stringValue = reader.Value.ToString();
 if (stringValue.Contains("[GMT]"))
 {
 stringValue = stringValue.Substring(0, stringValue.Length - 6);
 DateTime createdDate = DateTime.Parse(stringValue);
 return createdDate;
 }
 if (!long.TryParse((string)reader.Value, out ticks))
 {
 throw new JsonSerializationException("Cannot convert invalid value.");
 }
 }
 else
 {
 throw new JsonSerializationException("Unexpected token parsing date.");
 }
 if (ticks >= 0)
 {
 DateTime d = UnixEpoch.AddMilliseconds(ticks);
 Type t = objectType;
 if (t == typeof(DateTimeOffset))
 {
 return new DateTimeOffset(d, TimeSpan.Zero);
 }
 return d;
 }
 else
 {
 throw new JsonSerializationException("Cannot convert value that is before Unix epoch of 00:00:00 UTC on 1 January 1970.");
 }
 }
 }
}

Please help me to get this working.

asked Mar 22, 2020 at 21:40
1
  • In my opinion if the date field changes format you should just make it a string in your model and later on when you are going to use it then convert it. Also your model does not match property DateReveived. Commented Mar 22, 2020 at 21:47

2 Answers 2

0

You can't simply deserialise to an IList, you need an object that has an Items property. For example:

public class RootObject
{
 public IList<Item> Items { get; set; }
}

The other issue I can see is that the JsonProperty for your DateReceived property needs to match the JSON name which is just date.

answered Mar 22, 2020 at 21:44

Comments

0

Here is a full working sample:

this is my model:

 public class RootObject
 {
 public List<ItemContainer> Items { get; set; }
 }
 public class ItemContainer
 {
 public Item Item { get; set; }
 }
 public class Item
 {
 public Codes Codes { get; set; }
 public string Date { get; set; }
 public string Name { get; set; }
 public string Price { get; set; }
 }
 public class Codes
 {
 public string Productcode { get; set; }
 public string Departmentcode { get; set; }
 public string Storecode { get; set; }
 }

This is how I deserialize it:

var result = JsonConvert.DeserializeObject<RootObject>(json);//json is a string that contains the json input.

I have noticed several problems with your example:

  1. DataReceived is a property that does not exist in the json model.
  2. Your Json is inconsistent. Name, Date and Price are also found in lowercase: date, name and price. Your json should be consistent.
  3. You are trying to do too much in one spot. You should just take the input of date as a string and later on convert it to one or several useful formats or types. Keep your deserialization/serialization simple and save yourself headaches.
answered Mar 22, 2020 at 22:03

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.