0

Hi there I am trying to get to grips with Newtonsoft JsonConverter.
I have a .Net class which describes a business object, ScadaEvent, used in conjunction with List object as in:

 'ScadaEvent Object

 Public Class ScadaEvent
    Private _ID As Long
    Private _alarmID As String
    Private _alarmTime As Date
    Private _alarmUSECS As Integer
    Private _alarmInitialTime As Date
    Private _alarmInitialUsecs As Integer
    Private _alarmPriority As String
    Private _alarmType As String
    Private _alarmText As String
    Private _alarmText2 As String
    Private _AlarmComponentAlias As String
    Private _alarmDistrictZone As String
    Private _AlarmSubstationAlias As String
    Private _alarmSubstationName As String
    Private _alarmName As String
    Private _alarmBusbarNum As String
    Private _alarmCircuitRef As String
    Private _alarmCircuitName As String
    Private _deviceType As String
    Private _area As String
    Private _operatorAction As String
    Private _datasourceID As Long
    Private _localDateTime As Date
    Private _eventTime As String
    Private _interfaceConfiguration As String
    Private _dataSource As String
    Private _kpiStatus As String
    Private _supplementary As String
    Private _descriptor As String
    Private _PrimaryBusbar As String
    Private _PrimaryFeeder As String
    Private _fleetParams As String
    Private _CommsRoute As String

    Public Property ID() As Integer
        Get
            Return _ID
        End Get
        Set(ByVal value As Integer)
            _ID = value
        End Set
    End Property
    Public Property CommsRoute() As String
        Get
            Return _CommsRoute
        End Get
        Set(ByVal value As String)
            _CommsRoute = value
        End Set
    End Property
    Public Property FleetParams() As String
        Get
            Return _fleetParams
        End Get
        Set(ByVal value As String)
            _fleetParams = value
        End Set
    End Property

    Public Property Descriptor() As String
        Get
            Return _descriptor
        End Get
        Set(ByVal value As String)
            _descriptor = value
        End Set
    End Property

    Public Property Supplementary() As String
        Get
            Return _supplementary
        End Get
        Set(ByVal value As String)
            _supplementary = value
        End Set
    End Property

    Public Property AlarmID() As String
        Get
            Return _alarmID
        End Get
        Set(ByVal value As String)
            _alarmID = value
        End Set
    End Property

    Public Property AlarmTime() As Date
        Get
            Return _alarmTime
        End Get
        Set(ByVal value As Date)
            _alarmTime = value
        End Set
    End Property

    Public Property AlarmUsecs() As Integer
        Get
            Return _alarmUSECS
        End Get
        Set(ByVal value As Integer)
            _alarmUSECS = value
        End Set
    End Property

    Public Property AlarmInitialTime() As Date
        Get
            Return _alarmInitialTime
        End Get
        Set(ByVal value As Date)
            _alarmInitialTime = value
        End Set
    End Property

    Public Property AlarmInitialUsecs() As Integer
        Get
            Return _alarmInitialUsecs
        End Get
        Set(ByVal value As Integer)
            _alarmInitialUsecs = value
        End Set
    End Property

    Public Property AlarmPriority() As String
        Get
            Return _alarmPriority
        End Get
        Set(ByVal value As String)
            _alarmPriority = value
        End Set
    End Property

    Public Property AlarmType() As String
        Get
            Return _alarmType
        End Get
        Set(ByVal value As String)
            _alarmType = value
        End Set
    End Property

    Public Property AlarmText() As String
        Get
            Return _alarmText
        End Get
        Set(ByVal value As String)
            _alarmText = value
        End Set
    End Property

    Public Property AlarmText2() As String
        Get
            Return _alarmText2
        End Get
        Set(ByVal value As String)
            _alarmText2 = value
        End Set
    End Property


    Public Property AlarmComponentAlias() As String
        Get
            Return _AlarmComponentAlias
        End Get
        Set(ByVal value As String)
            _AlarmComponentAlias = value
        End Set
    End Property

    Public Property AlarmDistrictZone() As String
        Get
            Return _alarmDistrictZone
        End Get
        Set(ByVal value As String)
            _alarmDistrictZone = value
        End Set
    End Property

    Public Property AlarmSubstationAlias() As String
        Get
            Return _AlarmSubstationAlias
        End Get
        Set(ByVal value As String)
            _AlarmSubstationAlias = value
        End Set
    End Property

    Public Property AlarmSubstationName() As String
        Get
            Return _alarmSubstationName
        End Get
        Set(ByVal value As String)
            _alarmSubstationName = value
        End Set
    End Property

    Public Property AlarmName() As String
        Get
            Return _alarmName
        End Get
        Set(ByVal value As String)
            _alarmName = value
        End Set
    End Property

    Public Property AlarmBusbarNum() As String
        Get
            Return _alarmBusbarNum
        End Get
        Set(ByVal value As String)
            _alarmBusbarNum = value
        End Set
    End Property

    Public Property AlarmCircuitRef() As String
        Get
            Return _alarmCircuitRef
        End Get
        Set(ByVal value As String)
            _alarmCircuitRef = value
        End Set
    End Property

    Public Property AlarmCircuitName() As String
        Get
            Return _alarmCircuitName
        End Get
        Set(ByVal value As String)
            _alarmCircuitName = value
        End Set
    End Property

    Public Property DeviceType() As String
        Get
            Return _deviceType
        End Get
        Set(ByVal value As String)
            _deviceType = value
        End Set
    End Property

    Public Property Area() As String
        Get
            Return _area
        End Get
        Set(ByVal value As String)
            _area = value
        End Set
    End Property

    Public Property OperatorAction() As String
        Get
            Return _operatorAction
        End Get
        Set(ByVal value As String)
            _operatorAction = value
        End Set
    End Property

    Public Property DatasourceID() As Long
        Get
            Return _datasourceID
        End Get
        Set(ByVal value As Long)
            _datasourceID = value
        End Set
    End Property
    Public Property EventTime() As String
        Get
            Return _eventTime
        End Get
        Set(ByVal value As String)
            _eventTime = value
        End Set
    End Property

    Public Property Datasource() As String
        Get
            Return _dataSource
        End Get
        Set(ByVal value As String)
            _dataSource = value
        End Set
    End Property
    Public Property InterfaceConfiguration() As String
        Get
            Return _interfaceConfiguration
        End Get
        Set(ByVal value As String)
            _interfaceConfiguration = value
        End Set
    End Property

    Public Property LocalDateTime() As Date
        Get
            Return _localDateTime
        End Get
        Set(ByVal value As Date)
            _localDateTime = value
        End Set
    End Property

    Public Property KpiStatus() As String
        Get
            Return _kpiStatus
        End Get
        Set(ByVal value As String)
            _kpiStatus = value
        End Set
    End Property

    Public Property PrimaryBusbar() As String
        Get
            Return _PrimaryBusbar
        End Get
        Set(ByVal value As String)
            _PrimaryBusbar = value
        End Set
    End Property

    Public Property PrimaryFeeder() As String
        Get
            Return _PrimaryFeeder
        End Get
        Set(ByVal value As String)
            _PrimaryFeeder = value
        End Set
    End Property

End Class

ScadaEventList Object - A List of ScadaEvents

Public Class ScadaEventList
    Inherits List(Of ScadaEvent)

    Private _numCols As Integer = 28

    Public Sub New()
    End Sub

    Public ReadOnly Property Columns() As Integer
        Get
            Columns = _numCols
        End Get
    End Property
End Class

Here is the code which makes the call to the WebAPI which returns a JSON array serialized from a ScadaEvenList object in this instance the array contains a single element meeting the specified ID criterion:

Public Function FetchData() As ORG.Project.BusinessObject.ScadaEventList
    Dim response As String = Nothing
    Dim url As String = "http://DevMachine/api/events/GetEventsByID/229994213"
    Dim eList As ORG.Project.BusinessObject.ScadaEventList
    Using webClient As WebClient = New WebClient
        Dim json = webClient.DownloadString(url)
        eList = JsonConvert.DeserializeObject(Of ORG.Project.BusinessObject.ScadaEventList)(json)
    End Using
    Return elist
End Function

Unfortunately when the JsonConverter call is made it returns the following error:

{"Error converting value ""[{""ID"":229994213,""CommsRoute"":"""",""FleetParams"":null,""Descriptor"":""BUS SECTION STATE CHANGE ALM"",""Supplementary"":""BUS SECTION STATE CHANGE ALM TRIPPED"",""AlarmID"":""99999999ALRM"",""AlarmTime"":""2021-09-23T16:54:12"",""AlarmUsecs"":422,""AlarmInitialTime"":""2021-09-23T16:54:12"",""AlarmInitialUsecs"":422,""AlarmPriority"":""PRIORITY 1"",""AlarmType"":""INDICATION"",""AlarmText"":""OPEN"",""AlarmText2"":""TRIPPED"",""AlarmComponentAlias"":""888888888U"",""AlarmDistrictZone"":""CLYDE"",""AlarmSubstationAlias"":""77777777U"",""AlarmSubstationName"":""SUBNAME"",""AlarmName"":"""",""AlarmBusbarNum"":""99999"",""AlarmCircuitRef"":""99S"",""AlarmCircuitName"":""SUBNAME --> BUS SECTION"",""DeviceType"":""TELE CIRCUIT BREAKER - GMCB"",""Area"":""DISTRIBUTION"",""OperatorAction"":"""",""DatasourceID"":3,""EventTime"":""23/09/2021 16:54:12"",""Datasource"":""SCADASOURCE3"",""InterfaceConfiguration"":null,""LocalDateTime"":""2021-09-23T16:54:14"",""KpiStatus"":null,""PrimaryBusbar"":"""",""PrimaryFeeder"":""""}]"" to type 'SPEN.PSALERTS2021.BusinessObject.ScadaEventList'. Path '', line 1, position 1030."} Newtonsoft.Json.JsonSerializationException

I am new to using this function, however from my understanding of how it is supposed to be used this code should work.
Hoping someone out there can shed some light on this puzzler.
Note the data content is fake.

Edited with actual json returned by the WebClient call:

 "[{\"ID\":229994213,\"CommsRoute\":\"\",\"FleetParams\":null,\"Descriptor\":\"BUS SECTION STATE CHANGE ALM\",\"Supplementary\":\"BUS SECTION STATE CHANGE ALM TRIPPED\",\"AlarmID\":\"ObscuredALRM\",\"AlarmTime\":\"2021-09-23T16:54:12\",\"AlarmUsecs\":422,          \"AlarmInitialTime\":\"2021-09-23T16:54:12\",\"AlarmInitialUsecs\":422,\"AlarmPriority\":\"PRIORITY 1\",\"AlarmType\":\"INDICATION\",\"AlarmText\":\"OPEN\",\"AlarmText2\":\"TRIPPED\",\"AlarmComponentAlias\":\"ObscuredAlias\",\"AlarmDistrictZone\":\"ObscuredZone\",     \"AlarmSubstationAlias     \":\"ObscuredAlias\",\"AlarmSubstationName\":\"ObscuredSubstation\",\"AlarmName\":\"\",\"AlarmBusbarNum\":\"ObscuredNum\",\"AlarmCircuitRef\":\"ObscuredRef\",\"AlarmCircuitName\":\"ObscuredCct\",\"DeviceType\":\"TELE CIRCUIT BREAKER -     GMCB\",\"Area\":\"DISTRIBUTION\",\"OperatorAction     \":\"\",\"DatasourceID\":3,\"EventTime\":\"23/09/2021 16:54:12\",\"Datasource\":\"Datasource3\",\"InterfaceConfiguration\":null,\"LocalDateTime\":\"2021-09-23T16:54:14\",\"KpiStatus\":null,\"PrimaryBusbar\":\"\",        \"PrimaryFeeder\":\" \"}]"

Generated from Browser:

 <string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">[{"ID":229994213,"CommsRoute":"","FleetParams":null,"Descriptor":"BUS SECTION STATE CHANGE ALM","Supplementary":"BUS SECTION STATE CHANGE ALM TRIPPED","AlarmID":"ObscuredALRM","AlarmTime":"2021-09-23T16:54:12","AlarmUsecs":422,"AlarmInitialTime":"2021-09-23T16:54:12","AlarmInitialUsecs":422,"AlarmPriority":"PRIORITY 1","AlarmType":"INDICATION","AlarmText":"OPEN","AlarmText2":"TRIPPED","AlarmComponentAlias":"ObscuredAlias","AlarmDistrictZone":"ObscuredZon","AlarmSubstationAlias":"ObscuredAlias","AlarmSubstationName":"ObscuredSubstation","AlarmName":"","AlarmBusbarNum":"xxx","AlarmCircuitRef":"xx","AlarmCircuitName":"ObscuredCct","DeviceType":"TELE CIRCUIT BREAKER - GMCB","Area":"DISTRIBUTION","OperatorAction":"","DatasourceID":3,"EventTime":"23/09/2021 16:54:12","Datasource":"Datasource3","InterfaceConfiguration":null,"LocalDateTime":"2021-09-23T16:54:14","KpiStatus":null,"PrimaryBusbar":"","PrimaryFeeder":""}]</string>
Paul Johnson
  • 213
  • 3
  • 14
  • Are you actually receiving a JSON with double double-quotes? Because the error reports a problem at `line 1, position 1030`, but the JSON string is actually 915 characters long, when the duplicated quotes are removed, while it's 1036 chars including the duplicated quotes. -- The fixed JSON deserializes correctly using the model you posted here (btw, you don't need all those backing fields, you can use auto-properties). BTW2, you should use DateTimeOffset here, not Date. – Jimi Sep 24 '21 at 09:37
  • Anyway, difficult to say where there problem is if you don't post the real JSON (obscure *sensible* data if needed). – Jimi Sep 24 '21 at 09:50
  • Regarding the content of the json string, this is what the JsonConvert.Serialize method returns from the WebAPI so don't understand why it should have additional quotes in its content. – Paul Johnson Sep 24 '21 at 10:23
  • Ok... So I've tried to add the actual json content however the StackOverFlow editor is stripping out a whole series of backslashes '\'. Noted that it did this with the original post as well, which has perhaps mislead you somewhat. – Paul Johnson Sep 24 '21 at 10:30
  • Please, remove any additional character from the JSON string. Unless the string you're receiving is escaped as presented here. Otherwise, post the **real JSON**: what you exactly receive in that string. Don't copy the string from the debugger and don't add (or remove) anything, just post the output as it is. Printing to the Console, then select+copy, will do. Or use the `Text` debugger visualizer. – Jimi Sep 24 '21 at 11:25
  • Anyway, again, copying the JSON from the interface (not the string you pasted inside the editor, which is escaped), removing the leading and trailing double-quotes (which of course don't belong here), the JSON is deserialized correctly to your model. – Jimi Sep 24 '21 at 11:34
  • Jimi, OK... Think I've finally got there. See updated content in the post, this is a faithfull representation of the json received. – Paul Johnson Sep 24 '21 at 11:53
  • Jimi... Sorry don't know what happened there. Its definitely there now as a code entry as opposed to escaped text – Paul Johnson Sep 24 '21 at 13:07
  • If you don't know how to do any of what I described, then save the content to a file, encoded as UTF-8, then open it up and paste the content of that file. – Jimi Sep 24 '21 at 13:17
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/237456/discussion-between-paul-johnson-and-jimi). – Paul Johnson Sep 24 '21 at 13:18
  • It looks like your JSON may have been double-serialized by the server. The best way to handle that is to **fix the server**. For asp.net see [JSON.NET Parser *seems* to be double serializing my objects](https://stackoverflow.com/q/25559179/3744182) or [Strings sent through Web API's gets wrapped in quotes](https://stackoverflow.com/q/33681978/3744182). – dbc Sep 24 '21 at 15:15
  • **If you can't fix the server** you need to **deserialize twice** as shown in [this answer](https://stackoverflow.com/a/62783103/3744182) by [Brian Rogers](https://stackoverflow.com/users/10263/brian-rogers) to [Unable to deserialize JSON in C# using the same class at both ends](https://stackoverflow.com/q/62780693/3744182). In fact I would say your question is a duplicate of that one, agree? – dbc Sep 24 '21 at 15:20
  • This doesn't seem to be the case, because when called from the browser the output looks to be correct. I have added this to the main post under the sub-title Generated From Browser. – Paul Johnson Sep 24 '21 at 16:26
  • Your *Generated from Browser:* content is a JSON string that has been serialized as XML. Your *actual json returned by the WebClient call:* is a JSON string that has been serialized as JSON a second time. I don't know why your server is serializing to XML when responding to the browser, but it is. Anyway, have you tried deserializing twice as suggested in [Unable to deserialize JSON in C# using the same class at both ends.](https://stackoverflow.com/a/62783103/3744182)? It will take 5 minutes to test, and if it works it proves your JSON was double-serialized. – dbc Sep 24 '21 at 17:23

1 Answers1

0

Ok... So after running down multiple dead-ends, it turns out the solution to the problem was to remove the explicit jsonconvert.serialization command from the API. I I wasn't aware that objects were implicitly serialized in the WebAPI. Thanks Jimi for your feedback, it was much appreciated.

Paul Johnson
  • 213
  • 3
  • 14