skip to Main Content

I am running an ASP.NET Core 5 MVC project and tried to convert JSON response object from a Web API call to a list of ProductPromotionModels:

dynamic likesResult = await response.Content.ReadAsStringAsync(); 
var objs = Newtonsoft.Json.JsonConvert.DeserializeObject<List<ProductPromotionModel>>(likesResult.ToString());  

When I run this code in my application, I get this deserializing error:

Newtonsoft.Json.JsonSerializationException: Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type ‘System.TimeSpan’ because the type requires a JSON primitive value (e.g. string, number, boolean, null) to deserialize correctly. To fix this error either change the JSON to a JSON primitive value
(e.g. string, number, boolean, null) or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List) that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object.
Path ‘$values[0].startTime.ticks’, line 1, position 287

According to error message, the issue is in the startTime (Timespan property) property. So I have used JsonConverter, below is the json object:

{
  "$id": "1",
  "$values": [
    {
      "startTime": {
        "ticks": 36000000000,
        "days": 0,
        "hours": 1,
        "milliseconds": 0,
        "minutes": 0,
        "seconds": 0,
        "totalDays": 0.041666666666666664,
        "totalHours": 1,
        "totalMilliseconds": 3600000,
        "totalMinutes": 60,
        "totalSeconds": 3600
      },
      "endTime": {
        "ticks": 36000000000,
        "days": 0,
        "hours": 1,
        "milliseconds": 0,
        "minutes": 0,
        "seconds": 0,
        "totalDays": 0.041666666666666664,
        "totalHours": 1,
        "totalMilliseconds": 3600000,
        "totalMinutes": 60,
        "totalSeconds": 3600
      }
    }
  ]
}

Entity class

public partial class ProductPromotionModel 
{
    // ...

    [Display(Name = "Start Time")]
    [DataType(DataType.Time)]  
    [JsonConverter(typeof(TimeSpanToStringConverter), null)]
    public TimeSpan StartTime { get; set; }

    [Display(Name = "End Time")]
    [DataType(DataType.Time)]
    [JsonConverter(typeof(TimeSpanToStringConverter),null)]
    public TimeSpan EndTime { get; set; }
        
    // ...
}

Converter class

public class TimeSpanToStringConverter : JsonConverter<TimeSpan>
{
    public override TimeSpan ReadJson(JsonReader reader, Type objectType, TimeSpan existingValue, bool hasExistingValue, Newtonsoft.Json.JsonSerializer serializer)
    {
        int days = 0;
        int hours = 0;
        int minutes = 0;
        int seconds = 0;
        int milliseconds = 0;

        TimeSpan model = new TimeSpan();

        if (reader.TokenType != JsonToken.StartObject)
        {
            throw new Newtonsoft.Json.JsonException();
        }

        while (reader.Read())
        {
            if (reader.TokenType == JsonToken.EndObject)
            {
                break;
            }

            if (reader.TokenType == JsonToken.PropertyName)
            {
                string propertyName = reader.ReadAsString();                                

                switch (propertyName)
                {
                    case "days":
                        days = (int)reader.ReadAsInt32();
                        break;

                    case "hours":
                        hours = (int)reader.ReadAsInt32();
                        break;

                    case "milliseconds":
                        milliseconds = (int)reader.ReadAsInt32();
                        break;

                    case "minutes":
                        minutes = (int)reader.ReadAsInt32();
                        break;

                    case "seconds":
                        seconds = (int)reader.ReadAsInt32();
                        break;

                    default:
                        break;
                }
            }
        }

        if (reader.TokenType == JsonToken.EndObject)
        {
            model = new TimeSpan(days, hours, minutes, seconds, milliseconds);
        }

        return model;
    }

    public override void WriteJson(JsonWriter writer, TimeSpan value, Newtonsoft.Json.JsonSerializer serializer)
    {
        return;
    }
}

When I debug the converter, Propertyname show as numbers not the PropertyName as below. How can I get the PropertyName using JsonReader?

enter image description here

2

Answers


  1. Chosen as BEST ANSWER

    When I replace the code string propertyName = reader.ReadAsString() by string propertyName = reader.Value.ToString() issue was fixed in the converter class.

    Also startTime and EndTime getting from Sql Time Columns as below image:

    enter image description here


  2. you have a wrong syntax, read as a string always returns string, also converter could be much more simple

    string json = await response.Content.ReadAsStringAsync(); 
    
    List<ProductPromotionModel> models = JObject.Parse(json)["$values"]
                                         .ToObject<List<ProductPromotionModel>>();
    
    
    public class TimeSpanToStringConverter : JsonConverter<TimeSpan>
    {
        public override TimeSpan ReadJson(JsonReader reader, Type objectType, TimeSpan existingValue, bool hasExistingValue, Newtonsoft.Json.JsonSerializer serializer)
        {
            var o = JObject.Load(reader);
            return new TimeSpan( (int) o["days"], (int) o["hours"], (int) o["minutes"], (int) o["seconds"],(int) o["milliseconds"]);
        }
    
        public override void WriteJson(JsonWriter writer, TimeSpan value, JsonSerializer serializer)
        {
            throw new NotImplementedException();
        }
    
        public override bool CanWrite => false;
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search