There is no map for an object error when deserializing an object

I have the following C # code that should serialize arbitrary objects into a string, and then, of course, deserialize it.

public static string Pack(Message _message) { BinaryFormatter formatter = new BinaryFormatter(); MemoryStream original = new MemoryStream(); MemoryStream outputStream = new MemoryStream(); formatter.Serialize(original, _message); original.Seek(0, SeekOrigin.Begin); DeflateStream deflateStream = new DeflateStream(outputStream, CompressionMode.Compress); original.CopyTo(deflateStream); byte[] bytearray = outputStream.ToArray(); UTF8Encoding encoder = new UTF8Encoding(); string packed = encoder.GetString(bytearray); return packed; } public static Message Unpack(string _packed_message) { UTF8Encoding encoder = new UTF8Encoding(); byte[] bytearray = encoder.GetBytes(_packed_message); BinaryFormatter formatter = new BinaryFormatter(); MemoryStream input = new MemoryStream(bytearray); MemoryStream decompressed = new MemoryStream(); DeflateStream deflateStream = new DeflateStream(input, CompressionMode.Decompress); deflateStream.CopyTo(decompressed); // EXCEPTION decompressed.Seek(0, SeekOrigin.Begin); var message = (Message)formatter.Deserialize(decompressed); // EXCEPTION 2 return message; } 

But the problem is that at any time when the code runs, I experience an exception. Using the code above and calling it as shown below, I get an InvalidDataException: Unknown block type. The stream may be damaged. on the marked line // EXCEPTION .

After searching for this problem, I tried to thwart deflation. This was only a small change: in Pack , bytearray is created from original.ToArray() and Unpack , I Seek() input instead of decompressed and uses Deserialize(input) instead of decompressed too, the only result that has changed: exception position and body are different, but yet this is happening. I get a SerializationException: no map for object '201326592'. with // EXCEPTION 2 .

I don’t seem to see what the problem is. Perhaps this is the whole idea of ​​serialization ... the problem is that somehow managed to collect instances of Message , because these objects contain information that moves between the server and the client application. (The logic of Serialization is in a DLL project with the extension .Shared, which refers to both ends, however, right now, I only develop the server side first.) I also need to say that I use only string tags because right now there is a TCP connection between servers and customers based on reading and writing lines at the ends. So this should be reduced to string level.

Here's what the Message object looks like:

 [Serializable] public class Message { public MessageType type; public Client from; public Client to; public string content; } 

( Client now an empty class with a Serializable attribute, no properties or methods.)

Here's how the unpack package is called (from Main() ...):

  Shared.Message msg = Shared.MessageFactory.Build(Shared.MessageType.DEFAULT, new Shared.Client(), new Shared.Client(), "foobar"); string message1 = Shared.MessageFactory.Pack(msg); Console.WriteLine(message1); Shared.Message mess2 = Shared.MessageFactory.Unpack(message1); // Step into... here be exceptions Console.Write(mess2.content); 

Here is an image showing what is happening in the IDE. The output in the console window is message1 . Image showing the Exception happening and the output

Unfortunately, some studies have also shown that the problem may lie around the bytearray variable. When Pack() run after the encoder creates a string, the array contains 152 values; however, after it is decoded in Unpack() , the array has 160 instead.

I appreciate any help, because I am really out of ideas, and this problem is related to progress. Thanks.

(Update) Final Solution:

I would like to thank everyone who answered and commented on as I reached a solution. Thanks.

Mark Gravell was right, I missed the deflateStream closure, and because of this, the result was either empty or damaged. I spent my time and rethought and rewrote the methods, and now it works flawlessly. And even the goal of sending these bytes over the network stream also works.

Also, as Eric J. suggested, I switched to using ASCIIEnconding to change between string and byte[] when data flows in Stream .

The fixed code is below:

 public static string Pack(Message _message) { using (MemoryStream input = new MemoryStream()) { BinaryFormatter bformatter = new BinaryFormatter(); bformatter.Serialize(input, _message); input.Seek(0, SeekOrigin.Begin); using (MemoryStream output = new MemoryStream()) using (DeflateStream deflateStream = new DeflateStream(output, CompressionMode.Compress)) { input.CopyTo(deflateStream); deflateStream.Close(); return Convert.ToBase64String(output.ToArray()); } } } public static Message Unpack(string _packed) { using (MemoryStream input = new MemoryStream(Convert.FromBase64String(_packed))) using (DeflateStream deflateStream = new DeflateStream(input, CompressionMode.Decompress)) using (MemoryStream output = new MemoryStream()) { deflateStream.CopyTo(output); deflateStream.Close(); output.Seek(0, SeekOrigin.Begin); BinaryFormatter bformatter = new BinaryFormatter(); Message message = (Message)bformatter.Deserialize(output); return message; } } 

Now everything happens correctly, as shown below. This was the expected result from the first place. The server and client executables interact with each other, and the message moves ... and it becomes serialized and unesterialized.

Image showing proper output

+4
source share
3 answers

In addition to the existing observations about encoding against base-64, note that you did not close the deflation stream. This is important because the buffer of compressed threads: if you do not close, it cannot write the end. For a short stream, this may mean that he is not writing anything.

 using(DeflateStream deflateStream = new DeflateStream( outputStream, CompressionMode.Compress)) { original.CopyTo(deflateStream); } return Convert.ToBase64String(outputStream.GetBuffer(), 0, (int)outputStream.Length); 
+5
source

Your problem is most likely in UTF8 encoding. Your bytes are not really a character string, and UTF-8 is an encoding with different bytes for characters. This means that the byte array may not match the correctly encoded UTF-8 string (for example, some bytes may be missing at the end).

Try using UTF16 or ASCII, which are constant length encodings (the resulting string will most likely contain control characters, so it won’t print or pass through something like HTTP or email.)

But if you want to encode as a string, usually use UUEncoding to convert the byte array to a real printed string, then you can use whatever encoding you want.

+2
source

When I run the following Main () code on your Pack () and Unpack () package:

  static void Main(string[] args) { Message msg = new Message() { content = "The quick brown fox" }; string message1 = Pack(msg); Console.WriteLine(message1); Message mess2 = Unpack(message1); // Step into... here be exceptions Console.Write(mess2.content); } 

I see that bytearray

 byte[] bytearray = outputStream.ToArray(); 

is empty.

I modified your serialized class a bit since you did not send the code for the included classes

 public enum MessageType { DEFAULT = 0 } [Serializable] public class Message { public MessageType type; public string from; public string to; public string content; } 

I suggest the following steps to solve this problem:

  • Check out the intermediate results along the way. Do you also see 0 bytes in the array? What is the string value returned by Pack ()?
  • Dispose of your threads as soon as you are done with them. The easiest way to do this is with the using keyword.

Edit

As Eli and Marc correctly pointed out, you cannot store arbitrary bytes in a UTF8 string. The mapping is not bijective (you cannot go back and forth without losing / distorting information). You will need a mapping that is bijective, such as the Convert.ToBase64String () approach proposed by Mark.

+2
source

All Articles