Problems De-Serializing Data due to ObjectID? [C#/CS 2005]

Shaitan00

Junior Contributor
Joined
Aug 11, 2003
Messages
358
Location
Hell
I have made my own custom class to SERIALIZE and DE-SERIALIZE a custom object (kind of complicated, the object contains a custom array of custom objects, etc... lets just say I pretty much had to add [Serializable] at the top of all my objects).
Now the Serialization seems to work perfectly fine HOWEVER when I attempt to de-serialize the data on the other side (I send the data from the SERVER to the CLIENT via a TCP-Channel) I keep getting some odd errors regarding "objectID cannot be less than or equal to zero"

Anyways, this is the class I use to perform my Serialization
Code:
    public class Serialization
    {
        static private BinaryFormatter bf = new BinaryFormatter();

        public static byte[] Serialize(object data)
        {
            try
            {
                MemoryStream ms = new MemoryStream();
                bf.Serialize(ms, data);
                return ms.ToArray();
            }
            catch (Exception ex)
            {
                Log.Trace("Serialize:: General Exception: " + ex);
                return null;
            }
        }

        public static object Deserialize(byte[] data)
        {
            try
            {
                MemoryStream ms = new MemoryStream(data);
                return bf.Deserialize(ms);
            }
            catch (Exception ex)
            {
                Log.Trace("Deserialize:: General Exception: " + ex);
                return null;
            }
        }
    }
}

And this is the exact EXCEPTION error message I get (when caught) in the "Deserialize" function above...
[Exception]
Deserialize:: General Exception: System.ArgumentOutOfRangeException: objectID cannot be less than or equal to zero.
Parameter name: objectID
at System.Runtime.Serialization.ObjectManager.GetObject(Int64 objectID)
at System.Runtime.Serialization.Formatters.Binary.ObjectReader.ParseArrayMember(ParseRecord pr)
at System.Runtime.Serialization.Formatters.Binary.ObjectReader.ParseMember(ParseRecord pr)
at System.Runtime.Serialization.Formatters.Binary.ObjectReader.Parse(ParseRecord pr)
at System.Runtime.Serialization.Formatters.Binary.__BinaryParser.ReadMemberReference()
at System.Runtime.Serialization.Formatters.Binary.__BinaryParser.Run()
at System.Runtime.Serialization.Formatters.Binary.ObjectReader.Deserialize(HeaderHandler handler, __BinaryParser serParser, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream, HeaderHandler handler, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream)
at Application.Serialization.Deserialize(Byte[] data)
[/Exception]

I am totally lost and I can't seem to find any information regarding this type of error...
I must admit this is my first attempt at Serialization/DeSerialization of custom objects but I would have assumed it would work fine...

Any ideas, hints, and help would be greatly appreciated, thanks
 
Serialization issue or socket issue?

My first question would be - does the data deserialize correctly within the application that serialized it? Assuming that is the case, do you have any safeguards to check that the size of the data received is the same as the size of the data that was transmitted? The data may be fragmented in transit and arrive at the recipient in chunks, so the recipient must reassemble the data and not attempt deserialization until it has all been received.

Good luck :cool:
 
1- Looks like I am able to De-Serialize in the application itself (doesn't generate any errors when I .Serialize(Object) and right after .Deserialize(byte).. I would assume that means it works...

2- As for the sending of the data... I do it the following way:

-= SENDER =-
Code:
// Send Data Length
int nLen = byteData.Length;
byte[] byteLen = BitConverter.GetBytes(nLen);
nsClient.Write(byteLen, 0, 4);
nsClient.Flush();

// Send Data to Client
nsClient.Write(byteData, 0, byteData.Length);
nsClient.Flush();
Where NSCLIENT is a NETWORKSTREAM in conjunction with a TCP channel and BYTEDATA is the actual serialized data of my object.

-= RECIEVER =-
Code:
// Get Size
byte[] byteLen = new byte[4];
int nRecvLen = nsServer.Read(byteLen, 0, 4);
int nLen = BitConverter.ToInt32(byteLen, 0);

// Get Data
byte[] byteData = new byte[nLen];
int nRecvData = nsServer.Read(byteData, 0, nLen);
   // Use byteData to Deserialize into my custom object
Where NSSERVER is a NETWORKSTEAM in conjunction with a TCP channel...

I tried logging the sizes being sent and recieved [nLen] and they are the exact same thing ....

Shouldn't this ensure I recieved it all in one shot?
Am I going about this the wrong way?

Thanks,
 
Count the actual number of bytes!

Shaitan00 said:
I tried logging the sizes being sent and recieved [nLen] and they are the exact same thing ....

nLen appears to be your own variable, and is not necessarily equivalent to the actual number of bytes received. You need to keep reading until the actual number of bytes received equals nLen. Note that if this is in a callback function (eg asycnhronous sockets) then you will have to code in some logic to determine whether the incoming data is the beginning of a new set of data, or the next chunk of the last set of data.

For example:

C#:
//The variables nLenTotal, nLenCurrent and byteData MUST be persisted between events,
//i.e. they must be class-level variables

if (nLenTotal == 0) {
    //Must be the beginning of some new data
    //Get size
    byte[] byteLen = new byte[4];
    nRecvLen = nsServer.Read(byteLen, 0, 4);
    nLenTotal = BitConverter.ToInt32(byteLen, 0);

    //Initialize byte array
    byteData = new byte[nLenTotal];
    nLenCurrent = 0;
}

//Read some data
nRecvData = nsServer.Read(byteData, nLenCurrent, nLenTotal - nLenCurrent);
nLenCurrent += nRecvData;

if (nLenCurrent == nLenTotal) {
    //Received all data, now can deserialize
}
 
Works perfectly - thanks ... I had made a bad assumption that the entire data had been transfered in one single burst...
Thanks a lot !!!
 
Last edited:
Back
Top