C# Json Serializer Chokes on nested 'Shudown' value

I'm using the Newtonsoft JSON tools to deserialize a data request from an AF attribute, and it blows up when it reaches a nested value that is another JSON object with 'Shutdown' embedded in it, like this:

 

{"Timestamp":"2024-01-25T03:30:00Z","Value":{"Name":"Shutdown","Value":254,"IsSystem":true}}

 

In my serialization class I've tried using both 'object' and 'string' as the type for the Value property, but it chokes on both. So I am wondering if I need to filter out these values, and if so, how? Or is there another approach?

Parents
  • It would really help if you shared the relevant code for (1) the serialization class as well as (2) the snippet of HOW you are using it with a deserialize call. Let us know which version of .NET you are using. I have tested on .NET 6 and cannot reproduce your problem.

     

    The Value property should be an Object for 2 reasons. One, you may have many recorded values with different Value types (Integer, Single, Double), and Two, if a bad state is sent, then it would not match the expected Value type.

     

    I would encourage your class to include an IsGood property, if possible. Since the early 1990's, the OPC Foundation has declared a DA value to contain a minimum of 3 properties: (1) Time, (2) Value, and (3) Quality/Status.

     

    For simple enums, you may need to decorate the property, such as:

     

    [JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))]

    public object Value { get; set; }

     

    Though the ABOVE WILL NOT FIX your issue. You would use it when the property will always be an enum type.

     

    I want to know more about what is blowing up or throwing an exception when (A) Value is defined as object and (B) you are deserializing. Since you have provided ZERO code, I do not know if the actual deserialize call fails, or if it fails afterwards due to the complexity of Value.

     

  • I also captured the portion of the HTTP body that was causing the issue to verify it was the cause:

      String foo = "{\"Items\":[{\"Timestamp\":\"2024-01-01T08:00:00Z\",\"Value\":31.200000762939453},{\"Timestamp\":\"2024 - 01 - 25T03: 30:00Z\",\"Value\":{\"Name\":\"Shutdown\",\"Value\":254,\"IsSystem\":true}}]}";
                        Root<PiValue> fooClass = JsonConvert.DeserializeObject<Root<PiValue>>(foo);

    Which it was, and thows the same exception:

     

    "Cannot deserialize the current JSON object (e.g. {\"name\":\"value\"}) into type 'System.Object' because the type requires a JSON primitive value (e.g. string, number, boolean, null) to deserialize correctly.\r\nTo 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<T>) 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.\r\nPath 'Items[1].Value.Name', line 1, position 131."

     

     

  • I wrote a .NET Framework 4.7.2 app and CANNOT DUPLICATE the issue. This indicates to me that most likely YOU have a LOGIC bug of your own doing somewhere in the code that have not shared with us.

     

    // These class definitions are about as plain vanilla as you can get.
       
       internal class Root<T>
        {
            public List<T> Items { get; set; }  
        }
    
        internal class PiValue
        {
            public DateTime Timestamp { get; set; }
            public object Value { get; set; }
            public override string ToString() => $"{Value}, {Timestamp}";
        }

    And in Main(), I have

     

    String foo = "{\"Items\":[{\"Timestamp\":\"2024-01-01T08:00:00Z\",\"Value\":31.200000762939453},{\"Timestamp\":\"2024 - 01 - 25T03: 30:00Z\",\"Value\":{\"Name\":\"Shutdown\",\"Value\":254,\"IsSystem\":true}}]}";
    Root<PiValue> fooClass = JsonConvert.DeserializeObject<Root<PiValue>>(foo);
    Console.WriteLine(fooClass.Items.Count);

    And the Main() works perfectly fine. I think the problem is with your PC, environment, or your own code.

     

  • I've boiled it down to this using the defined classes above and partial HTTP response payload hardcoded as 'foo' below. I'm not hiding anything. This throws the exact same exception as if I were performing the HTTP request via HttpClient:

     try
    {
                        //This works
                        String fooNoShutdown = "{\"Items\":[{\"Timestamp\":\"2024-01-01T08:00:00Z\",\"Value\":111},{\"Timestamp\":\"2024-01-01T09:00:00Z\",\"Value\":222}]}";
                        Root<PiValue> fooClassWorking = JsonConvert.DeserializeObject<Root<PiValue>>(fooNoShutdown);
    
                        //This does not
                        String fooWithShutdown = "{\"Items\":[{\"Timestamp\":\"2024-01-01T08:00:00Z\",\"Value\":31.200000762939453},{\"Timestamp\":\"2024 - 01 - 25T03: 30:00Z\",\"Value\":{\"Name\":\"Shutdown\",\"Value\":254,\"IsSystem\":true}}]}";
                        Root<PiValue> fooClassNotWorking = JsonConvert.DeserializeObject<Root<PiValue>>(fooWithShutdown);
    }
    catch (Exception exxx)
    {
                        throw exxx;
    }

     

Reply
  • I've boiled it down to this using the defined classes above and partial HTTP response payload hardcoded as 'foo' below. I'm not hiding anything. This throws the exact same exception as if I were performing the HTTP request via HttpClient:

     try
    {
                        //This works
                        String fooNoShutdown = "{\"Items\":[{\"Timestamp\":\"2024-01-01T08:00:00Z\",\"Value\":111},{\"Timestamp\":\"2024-01-01T09:00:00Z\",\"Value\":222}]}";
                        Root<PiValue> fooClassWorking = JsonConvert.DeserializeObject<Root<PiValue>>(fooNoShutdown);
    
                        //This does not
                        String fooWithShutdown = "{\"Items\":[{\"Timestamp\":\"2024-01-01T08:00:00Z\",\"Value\":31.200000762939453},{\"Timestamp\":\"2024 - 01 - 25T03: 30:00Z\",\"Value\":{\"Name\":\"Shutdown\",\"Value\":254,\"IsSystem\":true}}]}";
                        Root<PiValue> fooClassNotWorking = JsonConvert.DeserializeObject<Root<PiValue>>(fooWithShutdown);
    }
    catch (Exception exxx)
    {
                        throw exxx;
    }

     

Children
No Data