BinaryFormatter exception
Asked Answered
P

1

8

I'm attempting to move an object graph from a server process to a client. And it works. At least it works when the both the client and server are on my dev virtual machine. It also works when I run the server on my base machine (client on dev vm).

It stops working though, when I run the server on my media centre PC. The exception is:

Binary stream '0' does not contain a valid BinaryHeader. Possible causes are invalid stream or object version change between serialization and deserialization.

All three PC's are x64 Windows 7 machines. I'm using TCPClient and TCPListener along with the BinaryFormatter class to do the heavy lifting.

The data being transferred is read from a file using a standard FileStream object.

If at the client end I serialize the buffers to a file, the contents (according to BeyondCompare) do actually seem to differ?!?

All string properties on my objects are Base64 encoded in the setters and decoded in the getters.

I can post code but I'm not sure where the problem area lies? Any ideas?

Pectize answered 10/4, 2011 at 5:2 Comment(2)
Make sure all the loaded assemblies are in fact the same versions and are the same assembly. Also, I dont understand the point of using Base64 encoding in a binary serialization scenario.Novelistic
@leppie, yup - all assemblies are definitely identical. The base64 thing was just added in a last gasp attempt to isolate any encoding weirdness - i'm definitely not an expert in using the BinaryFormatter.Pectize
P
1

Update: I've seemingly solved this issue. I had a breakpoint where the client read the server response

tcpClient.GetStream().Read(buffer, 0, buffer.Length);

and noted that fewer bytes were read from the "problem" server. After a quick google I found this article http://social.msdn.microsoft.com/Forums/en-US/ncl/thread/759f3f2f-347b-4bd8-aa05-fb7f681c3426 in which Dave Murray suggests:

There are a couple ways to handle this more elegantly. If you're not planning on reusing the connection for anything else, the easiest is what nobugz suggests. When the server is done sending data, have it Close() it's end of the connection. When the client has read all data sent before the Close, Read will start returning 0, at which point you know the server isn't planning on sending anything else.

So i updated my code from a single read to:

var buffer = new byte[32768];
var totalBytesRead = 0;
var bytesRead = tcpClient.GetStream().Read(buffer, 0, buffer.Length);

do
{
      totalBytesRead += bytesRead;
      bytesRead = tcpClient.GetStream().Read(buffer, totalBytesRead, bytesRead);

} while (bytesRead > 0);

and updated my server code to close the connection as per the post. And according to the comment from @leppie i can probably remove my Base64 wrapped properties...

Pectize answered 10/4, 2011 at 6:41 Comment(3)
Yeah, not checking the result of Read is a mistake. The fixed buffer is also a mistake, though - unless you know the length in advance. A preferred approach would be to push it into a MemoryStream. Or: just deserialize directly from the TCP stream.Anachronous
@Marc - Thanks, agree - this is POC code but that doesn't excuse bad coding. I'll remove the fixed size buffer and read directly into a memory stream for now. Re "deserializing straight from the TCP stream". My question would be that if the tcpClient is reading in chunks how would that work? You need to have the entire message read before deserializing?Pectize
because you have the TCP client as a Stream, you don't need the entire message; the caller can pick data off as it likesAnachronous

© 2022 - 2024 — McMap. All rights reserved.