JsonConvert.DeserializeObject - Current JsonReader item is not an object: StartArray

190 views Asked by At

I am trying to map the JSON nodes to my class using path and get an error when DeserializeObject. Error is thrown at JObject.Load(reader).

'Error reading JObject from JsonReader. Current JsonReader item is not an object: StartArray. Path '', line 1, position 1.'

Here is Json response;

var responseData = "[{\"Channels\":[{\"Channel\":55,\"DataRate\":60,\"Offset\":0,\"PreScaled\":{\"Flags\":null,\"Reading\":4.809,\"ValidPercentage\":100},\"RedactedPercentage\":0,\"Scaled\":{\"Flags\":null,\"Reading\":4.809,\"ValidPercentage\":100},\"SensorLabel\":\"FLOW\",\"SensorName\":\"Flow\",\"Slope\":1,\"UniqueId\":685100,\"UnitName\":\"Litres Per Minute\"},{\"Channel\":57,\"DataRate\":60,\"Offset\":0,\"PreScaled\":{\"Flags\":null,\"Reading\":60.43,\"ValidPercentage\":100},\"RedactedPercentage\":0,\"Scaled\":{\"Flags\":null,\"Reading\":60.43,\"ValidPercentage\":100},\"SensorLabel\":\"HUM\",\"SensorName\":\"Humidity\",\"Slope\":1,\"UniqueId\":685100,\"UnitName\":\"Percent\"}],\"Location\":{\"Altitude\":null,\"Latitude\":52.20175,\"Longitude\":-1.7266},\"Timestamp\":{\"Convention\":\"TimeBeginning\",\"Timestamp\":\"2023-05-29T10:23:00+00:00\"}},{\"Channels\":[{\"Channel\":55,\"DataRate\":60,\"Offset\":0,\"PreScaled\":{\"Flags\":null,\"Reading\":4.803,\"ValidPercentage\":100},\"RedactedPercentage\":0,\"Scaled\":{\"Flags\":null,\"Reading\":4.803,\"ValidPercentage\":100},\"SensorLabel\":\"FLOW\",\"SensorName\":\"Flow\",\"Slope\":1,\"UniqueId\":685100,\"UnitName\":\"Litres Per Minute\"}],\"Location\":{\"Altitude\":null,\"Latitude\":52.20175,\"Longitude\":-1.7266},\"Timestamp\":{\"Convention\":\"TimeBeginning\",\"Timestamp\":\"2023-05-29T10:22:00+00:00\"}}]";

ReferenceStationData jsonLatestData = JsonConvert.DeserializeObject<ReferenceStationData>(responseData, new JsonSerializerSettings{DateTimeZoneHandling = DateTimeZoneHandling.Utc});


    
    //holds the desired deserialization logic
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JObject jo = JObject.Load(reader);
        object targetObj = Activator.CreateInstance(objectType);
        foreach (PropertyInfo prop in objectType.GetProperties().Where(p => p.CanRead && p.CanWrite))
        {
            JsonPropertyAttribute att = prop.GetCustomAttributes(true).OfType<JsonPropertyAttribute>().FirstOrDefault();
            string jsonPath = att != null ? att.PropertyName : prop.Name;
            if (serializer.ContractResolver is DefaultContractResolver)
            {
                var resolver = (DefaultContractResolver)serializer.ContractResolver;
                jsonPath = resolver.GetResolvedPropertyName(jsonPath);
            }

            if (!Regex.IsMatch(jsonPath, @"^[a-zA-Z0-9_.-]+$"))
            {
            //throw new InvalidOperationException($"JProperties of JsonPathConverter can have only letters, numbers, underscores, hiffens and dots but name was ${jsonPath}."); // Array operations not permitted
            }

            JToken token = jo.SelectToken(jsonPath);
            if (token != null && token.Type != JTokenType.Null)
            {
                object value = token.ToObject(prop.PropertyType, serializer);
                prop.SetValue(targetObj, value, null);
            }
        }

        return targetObj;
    }

Here is my code example;

https://dotnetfiddle.net/wEUZ83

1

There are 1 answers

0
Panagiotis Kanavos On BEST ANSWER

Change the target type to an array or list, eg:

var settings = new JsonSerializerSettings{
    DateTimeZoneHandling = DateTimeZoneHandling.Utc
};
var stations= JsonConvert.DeserializeObject<ReferenceStationData[]>(
    responseData, 
    settings);

DeserializeObject will deserialize the data to the exact type you specify. You need to tell it to handle the JSON string as an array or object by specifying the correct type.