0

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

user1263981
  • 2,953
  • 8
  • 57
  • 98
  • Are you looking for something like `JsonPathConverter` from [this answer](https://stackoverflow.com/a/33094930) by Brian Rogers to [Can I specify a path in an attribute to map a property in my class to a child property in my JSON?](https://stackoverflow.com/q/33088462)? Or rather, did you base your code on that answer? If so, see https://stackoverflow.com/help/referencing. – dbc Jul 04 '23 at 17:27
  • 2
    Post your code in the question itself. The error suggests you're trying to deserialize the array into an object, eg `Product` instead of an array or list of objects, eg `List` or `Product[]` – Panagiotis Kanavos Jul 04 '23 at 17:28

1 Answers1

2

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.

Panagiotis Kanavos
  • 120,703
  • 13
  • 188
  • 236