VB.Net Serializing and Deserializing Private Members - Simple Example

I need to serialize any object (to xml, json, other - not really caring) for the purpose of passing / cloning, etc.

I found the newtonsoft.json library to be pretty easy to use for this, except that it doesn't serialize private members. I found examples in C # that seem to offer what I need using contracts, but I can't seem to get them to work.

I would appreciate a simple example:

eg.

 Class Person
     Private _NI as integer
     Public Name as string
End Class

      

I need two functions:

Function SerializePerson(P as person) as string

Function DeSerializePerson(SerializedText as string) as Person

      

Ideally, I want an approach that is easy to duplicate for any object.

+3


source to share


3 answers


The trick with Newtonsoft is to modify JsonSerializerSettings

and pass them to JsonConvert.SerializeObject

. This answer has full details of this change: fooobar.com/questions/149807 / ...

Edit

I didn't think the associated code was in C # since I work so often. My apologies. I have translated the code below:

Dim settings As New JsonSerializerSettings() With {.ContractResolver = New MyContractResolver()}
Dim json As String = JsonConvert.SerializeObject(obj, settings)

      



And the contract resolver:

Imports System.Reflection
Imports Newtonsoft.Json
Imports Newtonsoft.Json.Serialization

Public Class MyContractResolver
    Inherits DefaultContractResolver
    Protected Overrides Function CreateProperties(type As Type, memberSerialization As MemberSerialization) As IList(Of JsonProperty)
        Dim props = type.GetProperties(BindingFlags.Public Or BindingFlags.NonPublic Or BindingFlags.Instance).
                            Select(Function(p) MyBase.CreateProperty(p, memberSerialization)).
                            Union(type.GetFields(BindingFlags.Public Or BindingFlags.NonPublic Or BindingFlags.Instance).
                            Select(Function(f) MyBase.CreateProperty(f, memberSerialization))).ToList()

        props.ForEach(Sub(p)
                          p.Writable = True
                          p.Readable = True
                      End Sub)
        Return props
    End Function
End Class

      

Most code converters change C # Lambda to Function()

in VB.NET, but if they don't need a return type they should be converted to Sub()

. This was probably the cause of your problem.

+3


source


By using DataContractSerializer you put the things you want to serialize with the appropriate attribute. You didn't share what you tried or how it failed when you tried to use it, but here's how:

Imports System.Runtime.Serialization
Imports System.ComponentModel

<DataContract>
Public Class Employee
    <DataMember(Name:="Name")>
    Public Property Name As String

    <DataMember(Name:="Dept")>
    Public Property Dept As String

    <DataMember(Name:="Index")>
    Public Property Index As Integer

    <DataMember(Name:="secret")>
    Private secret As Integer

    ' most serializers require a simple ctor
    Public Sub New()

    End Sub

    Public Sub SetValue(n As Integer)
        secret = n
    End Sub

End Class

      

Use <DataContract>

for class and <Datamember>

for members. Then serialize:

' test data
Dim emp As New Employee With {.Name = "Ziggy", .Dept = "Manager", .Index = 2}
emp.SetValue(4)            ' set private member value

Dim ser = New DataContractSerializer(GetType(Employee))

Using fs As New FileStream("C:\Temp\DCTest.xml", FileMode.OpenOrCreate),
                      xw = XmlWriter.Create(fs)
    ser.WriteObject(xw, emp)
End Using

      

Output:

<?xml version="1.0" encoding="utf-8"?>
   <Employee xmlns:i="..." xmlns="...">
      <Dept>Manager</Dept>
      <Index>2</Index>
      <Name>Ziggy</Name>
      <secret>4</secret>
 </Employee>

      



As far as functions of the same size for all types of this type are concerned, I personally tend to view serialization as a class or application or specific task (I also prefer binary serialization over XML 100 to 1), but ...

Private Function SerializeToString(Of T)(obj As T) As String
    ' there might be more efficient ways...
    ' this is off the top of my head
    Dim ser = New DataContractSerializer(GetType(T))
    Dim xml As String

    Using ms As New MemoryStream()
        ser.WriteObject(ms, obj)
        ms.Position = 0
        Using sr As New StreamReader(ms)
            xml = sr.ReadToEnd
        End Using
    End Using

    Return xml
End Function

Public Function DeserializeFromString(Of T)(xmlString As String) As T

    Dim ser = New DataContractSerializer(GetType(T))
    Dim ret As T

    Using sr As New StringReader(xmlString),
        ms As New MemoryStream(Encoding.Default.GetBytes(sr.ReadToEnd))
        ret = CType(ser.ReadObject(ms), T)
    End Using

    Return ret

End Function

      

It seems that we are working in a "round" test:

Dim emp As New Employee With {.Name = "Ziggy", .Dept = "Manager", .Index = 2}
emp.SetValue(4)

Dim str = SerializeToString(Of Employee)(emp)

Dim emp2 As Employee = DeserializeFromString(Of Employee)(str)

' serialize to disk (not shown)
If SerializeToFile("C:\Temp\DCTest.xml", emp) Then

    Dim emp3 As Employee = DeserializeFromFile(Of Employee)("C:\Temp\DCTest.xml")

End If

      

The deserialized version has the correct private secret:

enter image description here

+2


source


I tried this a long time ago and found that the best solution was to use .NET inline binary serialization. This was most efficient when preserving internal class variables. Tactics like XML serializaiton often failed with complex classes I wrote, and when adding new members to the class, I often had to update the methods I wrote to implement IXmlSerializable.

The context was that I needed to pass code from the website to the web service - this was the only allowed way to pass data from the web zone through our firewall to our internal business servers. I wanted to pass all the object data to a web service to run some business logic and focus on the database bit.

The solution was binary serialization to a byte array - a valid input type for a web service - and binary deserialization in a web service.

An example of how to serialize, given a web service that returns a boolean result for sucess and assuming the object you want to serialize is called myObject

    dim result as boolean
    Dim myStream As New System.IO.MemoryStream()
    Dim myFormatter As New System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
    myFormatter.Serialize(myStream, myObject)  '1. Serialise into stream

    Dim bytes As Byte() = New Byte(myStream.Length) {}
    myStream.Position = 0
    myStream.Read(bytes, 0, myStream.Length)  '2. read stream into byte array

    result = myWebService.PersistObject(bytes) 

      

and here's a deserialization bit on the other end, assuming the object class was named widget and the data was passed to the methods as a variable called objectBytes

    Dim myWidget As New Widget
    Dim myStream As New System.IO.MemoryStream()
    Dim myFormatter As New System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
    myStream.Write(objectBytes, 0, objectBytes.Length)
    myStream.Position = 0
    myWidget = myFormatter.Deserialize(myStream)

      

Note that this requires the class libraries to be included that define the class on the host. But it's great that it works for any class

+1


source







All Articles