Problems with SoapFormatter and Deserialization

J

Jim S

I have an application where I have to make a tree of objects. To do
this, I have my own node class. At certain points in the application,
I need to save data. I am having a problem with the SoapFormatter.
The following program gets the exception: "The data at the root level
is invalid. Line 55, position -460."

This code works fine if I use a BinaryFormatter instead of a
SoapFormatter.
Any ideas? Here is a test program:


using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Soap;

namespace SoapTest
{
class MainClass
{
[STAThread]
static void Main(string[] args)
{
try
{
// Build up a very simple tree: a root with 4 children
MyNode root = new MyNode("Root Node", "The root of the
tree");
root.Add(new MyNode("Child 1", "Child node #1"));
root.Add(new MyNode("Child 2", "Child node #2"));
root.Add(new MyNode("Child 3", "Child node #3"));
root.Add(new MyNode("Child 4", "Child node #4"));

SoapFormatter sf = new SoapFormatter();
using (Stream strm = new FileStream("test.xml",
FileMode.OpenOrCreate, FileAccess.Write, FileShare.Write))
{
root.Save(strm, sf);
strm.Close();
}

using (Stream strm = new FileStream("test.xml",
FileMode.Open, FileAccess.Read, FileShare.Read))
{
root.Load(strm, sf);
strm.Close();
}

Console.WriteLine("Success.");
}
catch (Exception exc)
{
Console.WriteLine("An error occurred:");
Console.WriteLine(exc.Message);
}
Console.ReadLine();
}
}

public interface INamedObject
{
string Name { get; set; }
string Description { get; set; }
Guid Id { get; }
}

public interface INode : INamedObject
{
INode Parent { get; set; }
INode [] Children { get; }
void Add(INode child);
void Remove(INode child);
int IndexOf(INode child);
void Save(System.IO.Stream strm,
System.Runtime.Serialization.IFormatter formatter);
void Load(System.IO.Stream strm,
System.Runtime.Serialization.IFormatter formatter);
}

public class MyNode : INode
{
string name = "unnamed";
string description = "no description";
Guid guid = new Guid();
INode parent = null;
INode [] children = new INode[0];

public MyNode()
{
}

public MyNode(string name, string desc)
{
this.name = name;
this.description = desc;
}

#region INode Members

public INode Parent
{
get
{
return this.parent;
}
set
{
this.parent = value;
}
}

public INode[] Children
{
get
{
return this.children;
}
}

public void Add(INode child)
{
if (child==null) return; // don't allow null children
if (this.IndexOf(child)>=0) return; // don't allow duplicates
INode [] newList = new INode[this.children.Length+1];
this.children.CopyTo(newList, 0);
newList[this.children.Length] = child;
child.Parent = this;
this.children = newList;
}

public void Remove(INode child)
{
int index = this.IndexOf(child);
if (index<0) return;
INode [] newList = new INode[this.children.Length-1];
for (int ii=0 ; ii<index ; ii++)
newList[ii] = this.children[ii];
for (int ii=index ; ii<this.children.Length-1 ; ii++)
newList[ii] = this.children[ii+1];
this.children = newList;
child.Parent = null;
}

public int IndexOf(INode child)
{
for (int ii=0 ; ii<this.children.Length ; ii++)
if (this.children[ii] == child) return ii;
return -1;
}

public void Save(System.IO.Stream strm,
System.Runtime.Serialization.IFormatter formatter)
{
int version = 100;
formatter.Serialize(strm, version);
formatter.Serialize(strm, this.name);
formatter.Serialize(strm, this.description);
//formatter.Serialize(strm, this.guid);
formatter.Serialize(strm, this.children.Length);
foreach (INode child in this.children)
child.Save(strm, formatter);
}

public void Load(System.IO.Stream strm,
System.Runtime.Serialization.IFormatter formatter)
{
try
{
int version = (int)formatter.Deserialize(strm);
this.name = (string)formatter.Deserialize(strm);
this.description = (string)formatter.Deserialize(strm);
//this.guid = (Guid)formatter.Deserialize(strm);
int numKids = (int)formatter.Deserialize(strm);
this.children = new INode[numKids];
for (int ii=0 ; ii<numKids ; ii++)
{
this.children[ii] = new MyNode();
this.children[ii].Load(strm, formatter);
this.children[ii].Parent = this;
}
}
catch (Exception exc)
{
throw new Exception("MyNode.Load() exception", exc);
}
}

#endregion

#region INamedObject Members

public string Name
{
get
{
return this.name;
}
set
{
this.name = value;
}
}

public string Description
{
get
{
return this.description;
}
set
{
this.description = value;
}
}

public Guid Id
{
get
{
return this.guid;
}
}

#endregion
}
}
 
R

Robert Jordan

Jim said:
I have an application where I have to make a tree of objects. To do
this, I have my own node class. At certain points in the application,
I need to save data. I am having a problem with the SoapFormatter.
The following program gets the exception: "The data at the root level
is invalid. Line 55, position -460."

This code works fine if I use a BinaryFormatter instead of a
SoapFormatter.


The SoapFormatter supports only one Deserialize call per instance,
so you can use Serialize only once. I don't exactly know why.
You must redesign your code.

bye
Rob
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top