问题
I'm using JSON.NET to deserialize JSON responses from HTTP queries, but I'm stuck with an issue. That's because the response can send two types of object under same property, as shown below:
1st case sample (most common):
{
"type": "myType",
"tid": 4,
"action": "myAction",
"method": "myMethod",
"result": {
"success": true,
"total": 4,
"records": [
{
"id": 4,
"nome": "PRIMEIRO NOME",
"sigla": "PN"
},
{
"id": 1974,
"nome": "SEGUNDO NOME",
"sigla": "SN"
},
{
"id": 2584,
"nome": "TERCEIRO NOME",
"sigla": "TN"
},
{
"id": 1170,
"nome": "QUARTO NOME",
"sigla": "QN"
}
]
}
}
2nd case sample (rare):
{
"type": "myType",
"tid": 3,
"action": "myAction",
"method": "myMethod",
"result": [
{
"id": 4,
"nome": "PRIMEIRO NOME",
"sigla": "PN"
},
{
"id": 1974,
"nome": "SEGUNDO NOME",
"sigla": "SN"
},
{
"id": 2584,
"nome": "TERCEIRO NOME",
"sigla": "TN"
},
{
"id": 1170,
"nome": "QUARTO NOME",
"sigla": "QN"
}
]
}
I've been using these classes to receive data for the 1st case:
Public Class Record
Public Property id As Integer
Public Property nome As String
Public Property sigla As String
End Class
Public Class Result
Public Property success As Boolean
Public Property total As Integer
Public Property records As Record()
End Class
Public Class Response
Public Property type As String
Public Property tid As Integer
Public Property action As String
Public Property method As String
Public Property result As Result
End Class
So it worked well upon deserialization of 1st case JSON, with this statement:
Dim myResponse = JsonConvert.DeserializeObject(Of Response)(myJsonString)
However, when receiving 2nd case JSON, it creates object of type Response, stores in its property result an object of type Result whose properties remain empty, and the data which I needed to retrieve vanishes for it is stored nowhere.
I thought that I should modify the class Response so it has place for that different set of data, this way:
Public Class Response
Public Property type As String
Public Property tid As Integer
Public Property action As String
Public Property method As String
Public Property result As Result
Public Property resultRecords As Record()
End Class
The question, then, is this: how can I tell JsonConvert whether to store data in property Response.result when it fits its type (1st sample case above), or in Response.resultRecords in 2nd case?
Thank you!
回答1:
Since the format of the JSON can vary for the same property, you will need a custom JsonConverter to handle it. The converter can read the JSON for the affected property, determine its format and then populate your objects appropriately. Here is the code you would need:
Public Class ResultConverter
Inherits JsonConverter
Public Overrides Function CanConvert(objectType As Type) As Boolean
Return objectType = GetType(Result)
End Function
Public Overrides Function ReadJson(reader As JsonReader, objectType As Type, existingValue As Object, serializer As JsonSerializer) As Object
Dim token As JToken = JToken.Load(reader)
Dim result As Result = New Result
If token.Type = JTokenType.Array Then
result.records = token.ToObject(Of Record())(serializer)
result.total = result.records.Length
result.success = True
Else
serializer.Populate(token.CreateReader(), result)
End If
Return result
End Function
Public Overrides ReadOnly Property CanWrite As Boolean
Get
Return False
End Get
End Property
Public Overrides Sub WriteJson(writer As JsonWriter, value As Object, serializer As JsonSerializer)
Throw New NotImplementedException
End Sub
End Class
To use the converter, add a <JsonConverter>
attribute to the result
property in your Response
class:
Public Class Response
Public Property type As String
Public Property tid As Integer
Public Property action As String
Public Property method As String
<JsonConverter(GetType(ResultConverter))>
Public Property result As Result
End Class
Here is a working fiddle to show that this converter will allow both JSON formats to be deserialized into the same classes: https://dotnetfiddle.net/NFbQ2Q
来源:https://stackoverflow.com/questions/37054003/deserialize-json-which-can-have-different-objects-under-same-property-name