Solved

Deserializing older versions of classes that contain structs formatted with Soap

Posted on 2003-10-27
6
469 Views
Last Modified: 2008-03-17
Hi,
I previously released an application that uses the .Net in-build serialization. Ie, just adding [Serializable] to the top of each class. I would like to now make changes to some of the classes - but also have the newer version of my program be able to open files saved with the older version of my program.
It was my belief that I could use the .net [Serializable] attribute initially, and then move over to implementing ISerializable as I needed to further change specific classes. Generally this has worked well. But...

Any class serialised using just [Serializable] that also contains a field that's a struct seems to be unopenable once I implement ISerializable. Ie, if I use the new version of the program to open a file saved with the old version I get a SeralizationException: Top Object cannot be instantiated for element '_size'.

Old version of class...
[Serializable]
public class Test1
{
    string _name = null;
    Size _size = Size.Empty;
    ...
}

New version of class...
[Serializable]
public class Test1 : ISerializable
{
    string _name = null;
    Size _size = Size.Empty;
    int _newField = 0;
   
    protected Test1(SerializationInfo info, StreamingContext context)
    {
        // something... or nothing, in either case it doesn't work
    }
    public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        // usual stuff... not necessary for this test case
    }
}

I'm using the SoapFormatter to save/open objects
static object Load()
{
    IFormatter formatter = new SoapFormatter();
    Stream s = new FileStream("c:\\test.xml", FileMode.Open, FileAccess.Read, FileShare.Read);
    object loadedObject = formatter.Deserialize(s);
    s.Close();
    return loadedObject;
}

static void Save(object obj)
{
    Stream s = (Stream)File.Open("c:\\test.xml", FileMode.Create, FileAccess.Write);
    IFormatter b = new SoapFormatter();
    b.Serialize(s, obj);
    s.Close();
}

* If I do the whole experiment with the BinaryFormatter instead of the SoapFormatter, everything works perfectly. But the version of the product already out there is using the SoapFormatter.
Is this a bug in SoapFormatter?
* If the classes don't use structs, but just stick to classes, arrays and primitives, then I don't have any problems.

Is there anyway that I'm able to be able to open these older files, eg with some special Binder or something? Is this a bug in .net SoapFormatter maybe?
(I'd prefer to not manually process the whole XML file).

Any assistance appreciated, thanks.
0
Comment
Question by:paylett
  • 3
  • 2
6 Comments
 

Author Comment

by:paylett
ID: 9639342
I've tried experimenting with the Binder, and the SoapFormatter doesn't seem to call the Binder wrt the struct.
I'll push this up to 500 points.
0
 
LVL 10

Expert Comment

by:ptmcomp
ID: 9639929
The Soap formatter is made to serialize objects for using the soap protocol. It's not thought to make objects persistent for a longer time! So it's not a bug that you cannot deserialize "old" objects.
Use XmlSerializer where you can control the serialization by attributes to make your objects persistent in files or database.
0
 

Author Comment

by:paylett
ID: 9653898
Do you know of anyway that I would be able to read these older versions?
(I'd prefer to have the next version of my product backwards compatible if possible)
0
Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

 
LVL 10

Accepted Solution

by:
ptmcomp earned 500 total points
ID: 9663545
In Microsoft Developer Journal was an article from Jeffrey Richter about this serializing stuff explaining how to change the version dependency. (http://msdn.microsoft.com/msdnmag/issues/02/09/NET/default.aspx)
Else use the old version of your assembly to deserialize it. Either name the new assembly different or load the old assembly in a seperate application domain (else you cannot have both loaded at same time).
0
 

Author Comment

by:paylett
ID: 9667916
The Jeffrey Richter article is by far the best I've seen so far on serialization. However, I've tried using the SurrogateSelector and I still get the same Top Object can not be instantiated for element '_size' exception.

This just seems to be a short coming in the .net serialization wrt structs. The article by Richter points out other problems with structs and serialization - perhaps they know about this too.

For the moment I'll concede that either I'm using the wrong tool for the job, or it's an oversite by MS. Am going to move to the BinaryFormatter and tell users their old files can't be opened.
0
 

Expert Comment

by:MariaSimlinger
ID: 12541819
Hi,

I only signed up to experts exchange to see the solution for this problem. Nevertheless I had to find a solution on my own, I did find one, and I think I should share it with you.

I assume you tried to use the Binder class with the struct, and that didn't work.

Try to rename the old version of your class to something like Test1Old and inherit (a new) Test1 from this old version. Test1Old might have to be modified a little bit. The new version of Test1 implements ISerializable.

Set the AssemblyVersion from 1.0.0.0 to 2.0.0.0 (assuming 1.0.0.0 is your current version) and implement a Binder Class. But check for class Test1Old in the binder (see example). Register the Binder with the SoapFormatter (of course). It *will* be called during deserialization if you implement it this way!

To avoid casting problems in your Front-End implement IObjectReference on Test1Old.

// New version of class
[Serializable]
public class Test1 : Test1Old, ISerializable
{
   // only new properties go here
    ...
}

//Old version of class renamed, but IObjectReference returns new Version...
[Serializable]
public class Test1Old : IObjectReference
{
    string _name = null;
    Size _size = Size.Empty;
    int _newField = 0;

    // if necessary
    public Test1V2() : base()
   {
   }

    // GetRealObject is called after this object is deserialized.
    public Object GetRealObject(StreamingContext context)
    {
         if (this.GetType() != typeof(Test1Old))
               return this;
        Test1 t = new Test1();
        // set properties for t from *this*
       ...
    }
}

Check AssemblyVersion in Binder (thank’ to Jeffrey Richter for his great arcticle):

sealed class Ver1ToVer2DeserializationBinder : SerializationBinder {
   public override Type BindToType(
      string assemblyName, string typeName) {

      Type typeToDeserialize = null;

      // For each assemblyName/typeName that you wish to deserialize
      // to a different type, set typeToCreate to the desired type
      String assemVer1 = "MyAssem, Version=1.0.0.0, " +
         "Culture=neutral, PublicKeyToken=b77a5c561934e089";
      String typeVer1 = "Test1";

      if (assemblyName == assemVer1 && typeName == typeVer1) {
         assemblyName = assemblyName.Replace("1.0.0.0", "2.0.0.0");
      }

      // To return the type, do this:
      typeToDeserialize = Type.GetType(String.Format("{0}, {1}",
         "Test1Old", assemblyName));

      return typeToDeserialize;
   }
0

Featured Post

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
Data Saving 5 56
What .NET website keeps me current? 9 57
C# TextBox 11 30
Please explain "Multi-Tenant Services" 5 63
Introduction                                                 Was the var keyword really only brought out to shorten your syntax? Or have the VB language guys got their way in C#? What type of variable is it? All will be revealed.   Also called…
Summary: Persistence is the capability of an application to store the state of objects and recover it when necessary. This article compares the two common types of serialization in aspects of data access, readability, and runtime cost. A ready-to…
This Micro Tutorial will teach you how to censor certain areas of your screen. The example in this video will show a little boy's face being blurred. This will be demonstrated using Adobe Premiere Pro CS6.
Hi friends,  in this video  I'll show you how new windows 10 user can learn the using of windows 10. Thank you.

920 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

15 Experts available now in Live!

Get 1:1 Help Now