I'm new to JSON.NET and I'm trying to deserialize a JSON string to a simple .NET object containing a read-only property.
The JSON I'm trying to deserialize contains this read-only property (what is "wrong" of course). The problem is, that another property now doesn't get the value given in the JSON-string but the value of the read-only property. I would have expected JSON.NET throwing an error or simply ignoring the read-only property, but never getting another property the value of the read-only property. Am I missing something?
Or to put it in other words: Why does the value of DeSerPerson.Communications.Items(1).ComValue change, when the return statement of getEMail is changed?
As a workaround: How can I tell the serializer to serialize getEmail but the deserializer to ignore it, in case it is present?
I created a fiddle here: https://dotnetfiddle.net/tUMQxF slightly modified after the first answer.
Imports System
Imports System.Collections.Generic
Imports Newtonsoft.Json
Public Class Communication
Property ComType As Integer
Property ComValue As String
End Class
Public Class Communications
Private Property _fixedCommunication As New Communication With {.ComType = 2, .ComValue = "FixedEmail@web.de"}
Public Property Items As New List(Of Communication)
Public ReadOnly Property getEMail As Communication
Get
Return Items.Find(Function(x) x.ComType = 2) ' Yields unexpected result: DeSerPerson.Communications.Items(1).ComValue = Fred.Flintstone@web.de
'Return _fixedCommunication ' Yields expected result: DeSerPerson.Communications.Items(1).ComValue = NewEmailAddress@web.de, though "error" would be a more intuitive result to me
End Get
End Property
End Class
Public Class Person
Property Name As String
Property Communications As New Communications
End Class
Public Module Deserialization
Public Sub Main()
'The following Json-String was the result of the following process:
' 1. Deserialization of Person with Email-Address Fred.Flintstone@web.de
' 2. Sent to javascript via WebMethod
' 3. In javascript the Email-Address was changed to NewEmailAddress@web.de
' 4. The whole object (including the read-only property) was sent back resulting in the following JSON:
'Dim PersonJson = "
'{
' 'Name': 'Fred Flintstone'
' ,'Communications': {
' 'Items':[
' {'ComType':1,'ComValue':'0711-4665'}
' ,{'ComType':2,'ComValue':'NewEmailAddress@web.de'}
' ]
' ,'getEMail':
' {'ComType':2,'ComValue':'Fred.Flintstone@web.de'}
' }
'}".Replace("'", """")
Dim PersonJson = "{'Name': 'Fred Flintstone','Communications':{'Items':[{'ComType':1,'ComValue':'0711-4665'},{'ComType':2,'ComValue':'NewEmailAddress@web.de'}],'getEMail':{'ComType':2,'ComValue':'Fred.Flintstone@web.de'}}}".Replace("'", """")
Dim DeSerPerson = JsonConvert.DeserializeObject(Of Person)(PersonJson)
Console.WriteLine("Result for DeSerPerson.Communications.Items(1).ComValue:")
Console.WriteLine("--------------------------------------------------------")
Console.WriteLine("Expected : NewEmailAddress@web.de (or Error)")
Console.WriteLine("but result is: " & DeSerPerson.Communications.Items(1).ComValue) ' Fred.Flintstone@web.de
'Console.ReadLine()
End Sub
End Module
The explanation is easy. The deserializer just fills the values in the existing object, not create a new object and assign it to your property.
Note that the Readonly
modifier states that the value of the property (ie, the reference to the object) can't be changed but not the properties of the Communication
object itself.
In this case, your getEmail
property returns a reference to Items(1)
because that is the item with ComType = 2
.
As to "ignore" the object when deserializing, you can easily use a clone method. This way, you return the same values from getEmail
, but not the same object:
Add the clone method to Communication
:
Public Class Communication
Property ComType As Integer
Property ComValue As String
Public Function Clone() As Communication
Return New Communication() With {.ComType = Me.ComType, .ComValue = Me.ComValue}
End Function
End Class
Return the cloned object when reading the property:
Public ReadOnly Property getEMail As Communication
Get
Return Items.Find(Function(x) x.ComType = 2).Clone()
End Get
End Property
Of course this is not an optimum code. It's just to show you how the thing works :)