Refection/Serialization Problems

  • Thread starter Thread starter Russ
  • Start date Start date
R

Russ

Hi,

I'm trying to build a gerenic routine which deals with versioning problems
between serailized objects. All my objects are Serialized into a SQL
server DB, but I need to make changes to the object tree and also make
future changes easier.

I'm using custom serialization and reflection and I think I'm getting there,
but I have a wierd problem. I've extracted all the properties from the
object in question and passed the info to the following VB routine. It's
working fine until it encounters an invalid member in the serializationinfo
(which is expected - it's a newly added property in my object), but after
that it never recovers - from that point on I'm getting a
serializationexeption (member <name> not found) for each subsequent property
even when the member definitely exists in the serializationinfo. This only
happens AFTER the expected error, until then it's fine.

Any clues?

Thanks,
Russ

Private Shared Function CopyObject(ByVal Info As SerializationInfo, ByVal
PI() As PropertyInfo, ByRef O As Object)
Dim P As PropertyInfo
For Each P In PI
Try
P.SetValue(O, Info.GetValue(P.Name, P.PropertyType), Nothing)
Catch ex As Exception

End Try
Next
Return O
End Function
 
Hey Russ,

Did you serialize with the extra newly added property and the object you are
deserializing to did not contain it?

OR

You didn't serialize it in the first place, but your deserialization routine
needs to be smart enough to detect the presence or absence of that and add
..... say a default value of one doesn't exist in the serialized stream?

- Sahil Malik
Independent Consultant
You can reach me thru my blog at -
http://www.dotnetjunkies.com/weblog/sahilmalik/
 
Hi Russ,

I can not reproduce the problem.
I think you may try to take a look at the link below where has a sample
which demostrate how to do that. I think you may try the sample code first
to see if there is any different between your code and the sample code.

Run-time Serialization
http://msdn.microsoft.com/msdnmag/issues/02/04/net/

Run-time Serialization, Part 2
http://msdn.microsoft.com/msdnmag/issues/02/07/net/

Run-time Serialization, Part 3
http://msdn.microsoft.com/msdnmag/issues/02/09/net/


If you still have any concern, can you post a simple reproduce sample for
us to troubleshooting the problem?

Best regards,

Peter Huang
Microsoft Online Partner Support

Get Secure! - www.microsoft.com/security
This posting is provided "AS IS" with no warranties, and confers no rights.
 
Hi Sahil,

Thanks for the reply.

I've added the new property to the class, but the class I'm deserializing
doesn't yet contain it. I've had it working in the

Sub New (ByVal info As SerializationInfo, ByVal context As StreamingContext)

routine but the only way found I could do it is by creating a very long list
of hard wired code, for example:-

Try
Me.I_Address1 = info.GetString("I_Address1")
Me.I_Address2 = info.GetString("I_Address2")
Me.I_Address3 = info.GetString("I_Address3")
...
...

Catch

End Try


My 'top' object also contained other objects so I had to create a long list
for all these too (where a new property was introduced). This seemed a bit
inflexible and long winded so that's when I thought I could automate it by
scanning the properties of the current object definition and using
reflection and creating the original routine.

I see the problem now - it's deserializing ok until it hits the new
property, but it's not continuing on afterwards, which is exactly what I was
trying to make it do. So now I'm back to square one.

Am I missing something?

Thanks,
Russ
 
Russ, I believe you'd get your answer once you serialized it as
SoapFormatter and saw how dumb serialization is - it has to be - considering
that it is one size fits all. I can see why the code blows up when it tries
to deserialize something that it hadn't serialized to start with. There's a
tool called "Reflector" written by Lutz Roeder that will help you come to
the exact answer of "why" did it blow up - and I have an insinuation it
might be something to do with how streams work, I think every subsequent
property might be trying to be filled by property + 1 .. and so on and so
forth .. thats just a guess though.. but chances are that I am right ...

... anyway ... we know it fails, so lets not waste time on why .. instead
lets worry about how to not make it fail .. and yes I was able to reproduce
this problem. As an alternative approach, since you are trying to make your
deserialization process intelligent, and not try to deserialize what you had
never serialized. This approach might even be microsoft non-recommended, but
hey I know it'll work.

When you get the serializationinfo object, you can - using reflection read
it's private variables. One of the private variables you'll get will be
m_members, which is an array of strings which will tell you "What all did
you serialize in the first place". When you do so, you can only deserialize
what you had serialized in the first place and for the rest - generate
default values. That way, you routine will be 100% generic (Imagine that).
The reason probably why MS didn't do it was then this also opens pandora's
box that I can serialize a dog, and deserialize a cat out of it .. so be
careful with this extra power.

Another approach you could use is - if you are using Soapformatter (and this
approach is perfectly legal), you could load the XML in an XMLDocument and
go thru it and try and see what was Serialized, and again deserialize only
that. Unforunately you can't do this with any other formatters.

The only trick is not to try and deserialize what you hadn't serialized.

- Sahil Malik
Independent Consultant
You can reach me thru my blog at -
http://www.dotnetjunkies.com/weblog/sahilmalik/
 
Peter,

I was able to reproduce his problem .. .. create a class with 5 properties,
implement ISerializable, serialize it ..
then add a property somewhere in the middle and deserialize it back from
that same stream (file on ur pc). It blows up right there. I've had it blow
up if the data types don't match even.

- Sahil Malik
Independent Consultant
You can reach me thru my blog at -
http://www.dotnetjunkies.com/weblog/sahilmalik/
 
I have seen an article by Jeff Richter that suggests:
1. Versioning does matter - it includes checksums
2. The type in the assembly at the time deserialize is called must
match. So if you added fields to the text, the serialize will fail.

intrader

*** Sent via Devdex http://www.devdex.com ***
Don't just participate in USENET...get rewarded for it!
 
The type is stored just a text string .. so I guess it must be text matching
... and if he does get to the point where that one property fails, then
strings are all that are being matched .. though versioning could be a whole
another issue.

- Sahil Malik
Independent Consultant
You can reach me thru my blog at -
http://www.dotnetjunkies.com/weblog/sahilmalik/
 
Hi,

Thank you for your information.

Here is my reproduce sample.
Imports System
Imports System.IO
Imports System.Runtime.Serialization
Imports System.Runtime.Serialization.Formatters
Imports System.Runtime.Serialization.Formatters.Binary
Imports System.Runtime.Serialization.Formatters.Soap
Imports System.Reflection


<Serializable()> _
Class Manager
Implements ISerializable
Private _str1 As [String]
Private _str2 As [String]
Private _addstr As [String]
Private _str3 As [String]
Private _str4 As [String]
Private _str5 As [String]

Public Sub New()
_str1 = "str1"
_str2 = "str2"
_str3 = "str3"
_str4 = "str4"
_str5 = "str5"
End Sub 'New
Public Property Str1() As String
Get
Return _str1
End Get
Set(ByVal Value As String)
_str1 = Value
End Set
End Property
Public Property Str2() As String
Get
Return _str2
End Get
Set(ByVal Value As String)
_str2 = Value
End Set
End Property
Public Property addStr() As String
Get
Return _addstr
End Get
Set(ByVal Value As String)
_addstr = Value
End Set
End Property
Public Property Str3() As String
Get
Return _str3
End Get
Set(ByVal Value As String)
_str3 = Value
End Set
End Property
Public Property Str4() As String
Get
Return _str4
End Get
Set(ByVal Value As String)
_str4 = Value
End Set
End Property
Public Property Str5() As String
Get
Return _str5
End Get
Set(ByVal Value As String)
_str5 = Value
End Set
End Property
Public Sub GetObjectData(ByVal info As SerializationInfo, ByVal context
As StreamingContext) Implements ISerializable.GetObjectData
Dim thisType As Type = Me.GetType()
Dim mi As MemberInfo() =
FormatterServices.GetSerializableMembers(thisType, context)
Dim i As Int32
For i = 0 To mi.Length - 1
info.AddValue(mi(i).Name, CType(mi(i), FieldInfo).GetValue(Me))
Next i
End Sub


Protected Sub New(ByVal info As SerializationInfo, ByVal context As
StreamingContext)
Dim thisType As Type = Me.GetType()
Dim mi As MemberInfo() =
FormatterServices.GetSerializableMembers(thisType, context)
Dim i As Int32
For i = 0 To mi.Length - 1
Dim fi As FieldInfo = CType(mi(i), FieldInfo)
Try
Console.WriteLine("Extracting..." + fi.Name)
fi.SetValue(Me, info.GetValue(fi.Name, fi.FieldType))
Catch ex As Exception
Console.WriteLine(ex.ToString())
End Try
Next i
End Sub 'New
Public Overrides Function ToString() As [String]
Return [String].Format("{0} -> {1} -> {2} -> {3} -> {4} ", Str1,
Str2, Str3, Str4, Str5)
End Function
End Class
Class App
Public Shared Sub Main()
Dim formatter = New SoapFormatter

'Dim sm As New FileStream("Data.dat", FileMode.Create)
'Dim m As New Manager
'Console.WriteLine(m.ToString())
'formatter.Serialize(sm, m)
'sm.Close()

Dim sm As New FileStream("Data.dat", FileMode.Open)
Dim m As Manager = CType(formatter.Deserialize(sm), Manager)
sm.Close()
Console.WriteLine(m.ToString())
End Sub 'Main
End Class 'App

Reproduce steps.
1. Seriazlied 5 properties without the addstr into Data.dat
2. Add the addstr property and then deserialized the data.dat
3. Get exception and handle it the code will continue running.
output:
Extracting..._str1
Extracting..._str2
Extracting..._addstr
System.Runtime.Serialization.SerializationException: Member _addstr was not
found.
at System.Runtime.Serialization.SerializationInfo.GetElement(String
name, Type& foundType)
at System.Runtime.Serialization.SerializationInfo.GetValue(String name,
Typetype)
at CustomizedXML.Manager..ctor(SerializationInfo info, StreamingContext
context) in D:\NewsGroup\VB.NET\Console\CustomizedXML\Module1.vb:line 93
Extracting..._str3
Extracting..._str4
Extracting..._str5
str1 -> str2 -> str3 -> str4 -> str5


So can you post a simple reproduce sample so that we can troubleshooting
the problem.
If you have any misunderstanding ,please feel free to let me know.

Best regards,

Peter Huang
Microsoft Online Partner Support

Get Secure! - www.microsoft.com/security
This posting is provided "AS IS" with no warranties, and confers no rights.
 
Thanks Peter and Sahil,

I'll give it a go

Russ


"Peter Huang" said:
Hi,

Thank you for your information.

Here is my reproduce sample.
Imports System
Imports System.IO
Imports System.Runtime.Serialization
Imports System.Runtime.Serialization.Formatters
Imports System.Runtime.Serialization.Formatters.Binary
Imports System.Runtime.Serialization.Formatters.Soap
Imports System.Reflection


<Serializable()> _
Class Manager
Implements ISerializable
Private _str1 As [String]
Private _str2 As [String]
Private _addstr As [String]
Private _str3 As [String]
Private _str4 As [String]
Private _str5 As [String]

Public Sub New()
_str1 = "str1"
_str2 = "str2"
_str3 = "str3"
_str4 = "str4"
_str5 = "str5"
End Sub 'New
Public Property Str1() As String
Get
Return _str1
End Get
Set(ByVal Value As String)
_str1 = Value
End Set
End Property
Public Property Str2() As String
Get
Return _str2
End Get
Set(ByVal Value As String)
_str2 = Value
End Set
End Property
Public Property addStr() As String
Get
Return _addstr
End Get
Set(ByVal Value As String)
_addstr = Value
End Set
End Property
Public Property Str3() As String
Get
Return _str3
End Get
Set(ByVal Value As String)
_str3 = Value
End Set
End Property
Public Property Str4() As String
Get
Return _str4
End Get
Set(ByVal Value As String)
_str4 = Value
End Set
End Property
Public Property Str5() As String
Get
Return _str5
End Get
Set(ByVal Value As String)
_str5 = Value
End Set
End Property
Public Sub GetObjectData(ByVal info As SerializationInfo, ByVal context
As StreamingContext) Implements ISerializable.GetObjectData
Dim thisType As Type = Me.GetType()
Dim mi As MemberInfo() =
FormatterServices.GetSerializableMembers(thisType, context)
Dim i As Int32
For i = 0 To mi.Length - 1
info.AddValue(mi(i).Name, CType(mi(i), FieldInfo).GetValue(Me))
Next i
End Sub


Protected Sub New(ByVal info As SerializationInfo, ByVal context As
StreamingContext)
Dim thisType As Type = Me.GetType()
Dim mi As MemberInfo() =
FormatterServices.GetSerializableMembers(thisType, context)
Dim i As Int32
For i = 0 To mi.Length - 1
Dim fi As FieldInfo = CType(mi(i), FieldInfo)
Try
Console.WriteLine("Extracting..." + fi.Name)
fi.SetValue(Me, info.GetValue(fi.Name, fi.FieldType))
Catch ex As Exception
Console.WriteLine(ex.ToString())
End Try
Next i
End Sub 'New
Public Overrides Function ToString() As [String]
Return [String].Format("{0} -> {1} -> {2} -> {3} -> {4} ", Str1,
Str2, Str3, Str4, Str5)
End Function
End Class
Class App
Public Shared Sub Main()
Dim formatter = New SoapFormatter

'Dim sm As New FileStream("Data.dat", FileMode.Create)
'Dim m As New Manager
'Console.WriteLine(m.ToString())
'formatter.Serialize(sm, m)
'sm.Close()

Dim sm As New FileStream("Data.dat", FileMode.Open)
Dim m As Manager = CType(formatter.Deserialize(sm), Manager)
sm.Close()
Console.WriteLine(m.ToString())
End Sub 'Main
End Class 'App

Reproduce steps.
1. Seriazlied 5 properties without the addstr into Data.dat
2. Add the addstr property and then deserialized the data.dat
3. Get exception and handle it the code will continue running.
output:
Extracting..._str1
Extracting..._str2
Extracting..._addstr
System.Runtime.Serialization.SerializationException: Member _addstr was not
found.
at System.Runtime.Serialization.SerializationInfo.GetElement(String
name, Type& foundType)
at System.Runtime.Serialization.SerializationInfo.GetValue(String name,
Typetype)
at CustomizedXML.Manager..ctor(SerializationInfo info, StreamingContext
context) in D:\NewsGroup\VB.NET\Console\CustomizedXML\Module1.vb:line 93
Extracting..._str3
Extracting..._str4
Extracting..._str5
str1 -> str2 -> str3 -> str4 -> str5


So can you post a simple reproduce sample so that we can troubleshooting
the problem.
If you have any misunderstanding ,please feel free to let me know.

Best regards,

Peter Huang
Microsoft Online Partner Support

Get Secure! - www.microsoft.com/security
This posting is provided "AS IS" with no warranties, and confers no rights.
 
Peter,

It worked like a dream. Many thanks to you and Sahil for your kind help.

Russ


Russ said:
Thanks Peter and Sahil,

I'll give it a go

Russ


"Peter Huang" said:
Hi,

Thank you for your information.

Here is my reproduce sample.
Imports System
Imports System.IO
Imports System.Runtime.Serialization
Imports System.Runtime.Serialization.Formatters
Imports System.Runtime.Serialization.Formatters.Binary
Imports System.Runtime.Serialization.Formatters.Soap
Imports System.Reflection


<Serializable()> _
Class Manager
Implements ISerializable
Private _str1 As [String]
Private _str2 As [String]
Private _addstr As [String]
Private _str3 As [String]
Private _str4 As [String]
Private _str5 As [String]

Public Sub New()
_str1 = "str1"
_str2 = "str2"
_str3 = "str3"
_str4 = "str4"
_str5 = "str5"
End Sub 'New
Public Property Str1() As String
Get
Return _str1
End Get
Set(ByVal Value As String)
_str1 = Value
End Set
End Property
Public Property Str2() As String
Get
Return _str2
End Get
Set(ByVal Value As String)
_str2 = Value
End Set
End Property
Public Property addStr() As String
Get
Return _addstr
End Get
Set(ByVal Value As String)
_addstr = Value
End Set
End Property
Public Property Str3() As String
Get
Return _str3
End Get
Set(ByVal Value As String)
_str3 = Value
End Set
End Property
Public Property Str4() As String
Get
Return _str4
End Get
Set(ByVal Value As String)
_str4 = Value
End Set
End Property
Public Property Str5() As String
Get
Return _str5
End Get
Set(ByVal Value As String)
_str5 = Value
End Set
End Property
Public Sub GetObjectData(ByVal info As SerializationInfo, ByVal context
As StreamingContext) Implements ISerializable.GetObjectData
Dim thisType As Type = Me.GetType()
Dim mi As MemberInfo() =
FormatterServices.GetSerializableMembers(thisType, context)
Dim i As Int32
For i = 0 To mi.Length - 1
info.AddValue(mi(i).Name, CType(mi(i), FieldInfo).GetValue(Me))
Next i
End Sub


Protected Sub New(ByVal info As SerializationInfo, ByVal context As
StreamingContext)
Dim thisType As Type = Me.GetType()
Dim mi As MemberInfo() =
FormatterServices.GetSerializableMembers(thisType, context)
Dim i As Int32
For i = 0 To mi.Length - 1
Dim fi As FieldInfo = CType(mi(i), FieldInfo)
Try
Console.WriteLine("Extracting..." + fi.Name)
fi.SetValue(Me, info.GetValue(fi.Name, fi.FieldType))
Catch ex As Exception
Console.WriteLine(ex.ToString())
End Try
Next i
End Sub 'New
Public Overrides Function ToString() As [String]
Return [String].Format("{0} -> {1} -> {2} -> {3} -> {4} ", Str1,
Str2, Str3, Str4, Str5)
End Function
End Class
Class App
Public Shared Sub Main()
Dim formatter = New SoapFormatter

'Dim sm As New FileStream("Data.dat", FileMode.Create)
'Dim m As New Manager
'Console.WriteLine(m.ToString())
'formatter.Serialize(sm, m)
'sm.Close()

Dim sm As New FileStream("Data.dat", FileMode.Open)
Dim m As Manager = CType(formatter.Deserialize(sm), Manager)
sm.Close()
Console.WriteLine(m.ToString())
End Sub 'Main
End Class 'App

Reproduce steps.
1. Seriazlied 5 properties without the addstr into Data.dat
2. Add the addstr property and then deserialized the data.dat
3. Get exception and handle it the code will continue running.
output:
Extracting..._str1
Extracting..._str2
Extracting..._addstr
System.Runtime.Serialization.SerializationException: Member _addstr was not
found.
at System.Runtime.Serialization.SerializationInfo.GetElement(String
name, Type& foundType)
at System.Runtime.Serialization.SerializationInfo.GetValue(String name,
Typetype)
at CustomizedXML.Manager..ctor(SerializationInfo info, StreamingContext
context) in D:\NewsGroup\VB.NET\Console\CustomizedXML\Module1.vb:line 93
Extracting..._str3
Extracting..._str4
Extracting..._str5
str1 -> str2 -> str3 -> str4 -> str5


So can you post a simple reproduce sample so that we can troubleshooting
the problem.
If you have any misunderstanding ,please feel free to let me know.

Best regards,

Peter Huang
Microsoft Online Partner Support

Get Secure! - www.microsoft.com/security
This posting is provided "AS IS" with no warranties, and confers no rights.
 
Back
Top