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;
    }

     

  • I used your fooWithShutdown string and it worked perfectly fine for me.

     

    You used PiValue for the deserialization but the class your shared earlier is called PiValue2.

    // PiValue class used but you only have shared a PiValue2 class
    Root<PiValue> fooClassNotWorking = JsonConvert.DeserializeObject<Root<PiValue>>

    What does the class definition for PiValue look like? OR what happens if you deserialized to Root<PIValue2> ?

     

    Again, the problem is not reproducible. Have you stepped through the debugger for the Value property's setter to trace down your issue?

     

     

  • PIValue and PIValue2 are the same class. One had Value as a string property, but I had since changed back after your comment that it should be an object type. I just tried using the PIValue2 and got the same exception.

    I have stepped through the debugger with "step into property" option turned on. The first json object steps into both Timestamp and Value setters, and works just fine. The second, the one with the 'Shutdown' object, steps into Timestamp but it throws the exception before stepping into the Value setter.

    A compiled version of this throws the same exception on a coworker's computer. I guess that doesn't rule out the environment since they're probably pretty similar.

     

     

     

Reply
  • PIValue and PIValue2 are the same class. One had Value as a string property, but I had since changed back after your comment that it should be an object type. I just tried using the PIValue2 and got the same exception.

    I have stepped through the debugger with "step into property" option turned on. The first json object steps into both Timestamp and Value setters, and works just fine. The second, the one with the 'Shutdown' object, steps into Timestamp but it throws the exception before stepping into the Value setter.

    A compiled version of this throws the same exception on a coworker's computer. I guess that doesn't rule out the environment since they're probably pretty similar.

     

     

     

Children
No Data