A
Alex Zhitlenok
Hi,
In our system, we use a lot of referenced objects. We use binary
serialization for saving the objects and deserialization for
restoring. It worked, and we had no problem.
In a new version of our system, a lot of changes were done: some
classes were moved from assembly to assembly, others changed their
names, or have the same names but changed their fields list.
Obviously, the new version must read files that were saved in the
previous version.
To do that, I
1. Implemented empty surrogate classes for all classes that were
serialized;
2. Created Binder that binds all old types to new surrogate types;
3. Created BinaryFormatter and set its Binder property to my Binder
object.
4. Created surrogate deserializer object that implemented
SetObjectData(…) methods for each surrogate classes;
5. Created SurrogateSelector, which contains all my surrogate types
and corresponding surrogate deserializers.
6. SurrogateSelector property of the BinaryFormatter object was set to
my SurrogateSelector.
My first approach was just to deserialize binary stream to nothing,
add some necessary fields to my surrogate classes, and use them in
further restoring.
For all classes but one, the schema works fine. During
deserialization, old classes types are substituted with corresponded
surrogate classes types, SetObjectData(…) method is called for
surrogate deserialize and all info could be extracted from
SerializationInfo object.
Unfortunately one of the old classes was derived from WeakReference
class. After SetObjectData(…) is called for surrogate class, an
exception "Insufficient state to deserialize the object" is thrown.
Actually, I am not interested in this WeakReference object and would
be glad to skip its deserialization or ignore the exception.
Any suggestions are highly appreciated.
Here is some codes extraction (if someone wants to investigate the
problem I can send 30k binary stream).
//Binder
public class Assembly2AssemblyDeserializationBinder :
System.Runtime.Serialization.SerializationBinder
{
public override Type BindToType(String assemblyName, string
typeName)
{
//code to substitute all old classes with new ones
}
}
//Formatter Factory – returns BinaryFormatter and set surrogates for
//all new classes
public class V23FormatterFactory
{
public static IFormatter CreateVersionBinaryFormatter()
{
SurrogateSelector selector = new SurrogateSelector();
// adds all new surrogate classes types to selector and
// sets that V23Deserializer object must be used
selector.AddSurrogate( type,
new StreamingContext(StreamingContextStates.All),
new V23Deserializer());
BinaryFormatter bf = new BinaryFormatter();
bf.SurrogateSelector = selector;
return bf;
}
}
//surrogate deserialized
public class V23Deserializer : ISerializationSurrogate
{
public Object SetObjectData(
object obj,
SerializationInfo info,
StreamingContext context,
ISurrogateSelector selector
)
{
if( obj.GetType() == … )
{
//does nothing
}
else if( obj.GetType() == Type.GetType("SurrogateWeakRef"))
{
//does nothing
//and throws an exception "Insufficient state..."
//after the return
}
return obj;
}
}
//
// Main call for deserialization
//
IFormatter vFormatter =
V23FormatterFactory.CreateVersionBinaryFormatter();
vFormatter.Binder = new Assembly2AssemblyDeserializationBinder();
Object alSaved = vFormatter.Deserialize(sStream);
In our system, we use a lot of referenced objects. We use binary
serialization for saving the objects and deserialization for
restoring. It worked, and we had no problem.
In a new version of our system, a lot of changes were done: some
classes were moved from assembly to assembly, others changed their
names, or have the same names but changed their fields list.
Obviously, the new version must read files that were saved in the
previous version.
To do that, I
1. Implemented empty surrogate classes for all classes that were
serialized;
2. Created Binder that binds all old types to new surrogate types;
3. Created BinaryFormatter and set its Binder property to my Binder
object.
4. Created surrogate deserializer object that implemented
SetObjectData(…) methods for each surrogate classes;
5. Created SurrogateSelector, which contains all my surrogate types
and corresponding surrogate deserializers.
6. SurrogateSelector property of the BinaryFormatter object was set to
my SurrogateSelector.
My first approach was just to deserialize binary stream to nothing,
add some necessary fields to my surrogate classes, and use them in
further restoring.
For all classes but one, the schema works fine. During
deserialization, old classes types are substituted with corresponded
surrogate classes types, SetObjectData(…) method is called for
surrogate deserialize and all info could be extracted from
SerializationInfo object.
Unfortunately one of the old classes was derived from WeakReference
class. After SetObjectData(…) is called for surrogate class, an
exception "Insufficient state to deserialize the object" is thrown.
Actually, I am not interested in this WeakReference object and would
be glad to skip its deserialization or ignore the exception.
Any suggestions are highly appreciated.
Here is some codes extraction (if someone wants to investigate the
problem I can send 30k binary stream).
//Binder
public class Assembly2AssemblyDeserializationBinder :
System.Runtime.Serialization.SerializationBinder
{
public override Type BindToType(String assemblyName, string
typeName)
{
//code to substitute all old classes with new ones
}
}
//Formatter Factory – returns BinaryFormatter and set surrogates for
//all new classes
public class V23FormatterFactory
{
public static IFormatter CreateVersionBinaryFormatter()
{
SurrogateSelector selector = new SurrogateSelector();
// adds all new surrogate classes types to selector and
// sets that V23Deserializer object must be used
selector.AddSurrogate( type,
new StreamingContext(StreamingContextStates.All),
new V23Deserializer());
BinaryFormatter bf = new BinaryFormatter();
bf.SurrogateSelector = selector;
return bf;
}
}
//surrogate deserialized
public class V23Deserializer : ISerializationSurrogate
{
public Object SetObjectData(
object obj,
SerializationInfo info,
StreamingContext context,
ISurrogateSelector selector
)
{
if( obj.GetType() == … )
{
//does nothing
}
else if( obj.GetType() == Type.GetType("SurrogateWeakRef"))
{
//does nothing
//and throws an exception "Insufficient state..."
//after the return
}
return obj;
}
}
//
// Main call for deserialization
//
IFormatter vFormatter =
V23FormatterFactory.CreateVersionBinaryFormatter();
vFormatter.Binder = new Assembly2AssemblyDeserializationBinder();
Object alSaved = vFormatter.Deserialize(sStream);