Solved

Deserializing older versions of classes that contain structs formatted with Soap

Posted on 2003-10-27
6
499 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 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
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
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

VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

Question has a verified solution.

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

Introduction Although it is an old technology, serial ports are still being used by many hardware manufacturers. If you develop applications in C#, Microsoft .NET framework has SerialPort class to communicate with the serial ports.  I needed to…
It was really hard time for me to get the understanding of Delegates in C#. I went through many websites and articles but I found them very clumsy. After going through those sites, I noted down the points in a easy way so here I am sharing that unde…
In this video we outline the Physical Segments view of NetCrunch network monitor. By following this brief how-to video, you will be able to learn how NetCrunch visualizes your network, how granular is the information collected, as well as where to f…
Michael from AdRem Software outlines event notifications and Automatic Corrective Actions in network monitoring. Automatic Corrective Actions are scripts, which can automatically run upon discovery of a certain undesirable condition in your network.…

623 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