反序列化对象时没有对象错误的映射

Whi*_*ity 7 c# encoding serialization object stream

我有以下C#代码,它应该将任意对象序列化为字符串,然后当然反序列化它.

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;
}
Run Code Online (Sandbox Code Playgroud)

但问题是,无论何时运行代码,我都会遇到异常.使用上面的代码并调用它,如下所示,我收到InvalidDataException:未知的块类型.流可能已损坏.在标记的// EXCEPTION行.

在寻找这个问题之后,我试图放弃通缩.这只是一个很小的改变:in Pack,bytearrayfrom original.ToArray()和in in Unpack,我Seek() input代替decompressed和使用Deserialize(input)而不是decompressed.唯一改变的结果是:异常位置和身体是不同的,但它仍然发生.我收到一个SerializationException:没有对象'201326592'的映射.// EXCEPTION 2.

我似乎没有看到什么问题.也许这是整个序列化的想法...问题是,不知何故管理到包装Message情况下是必要的,因为这些对象保存在服务器和客户端应用程序之间传输的信息.(序列化逻辑在一个.Shared DLL项目中,在两端引用,但是,现在,我只是首先开发服务器端.)还必须告诉我,我现在只使用string输出,服务器和客户端之间的TCP连接基于端部的字符串读写.所以不得不将它降低到字符串的水平.

这是Message对象的样子:

[Serializable]
public class Message
{
    public MessageType type;
    public Client from;
    public Client to;
    public string content;
}
Run Code Online (Sandbox Code Playgroud)

(Client现在是一个只有Serializable属性,没有属性或方法的空类.)

这就是如何调用pack-unpack(来自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);
Run Code Online (Sandbox Code Playgroud)

这是一个显示IDE中发生的事情的图像.控制台窗口中的输出值为message1. 显示异常发生和输出的图像

不幸的是,一些调查还显示问题可能存在于bytearray变量周围.在运行时Pack(),在编码器创建字符串之后,该数组包含152个值,但是,在解码后Unpack(),该数组具有160个值.

我很感激任何帮助,因为我真的没有想法,并且遇到这个问题,进展就会瘫痪.谢谢.

(更新)最终解决方案:

我要感谢所有回答和评论的人,因为我已经达成了解决方案.谢谢.

Marc Gravell是对的,我错过了结束deflateStream,因此,结果是空的或损坏的.我花了很多时间重新思考并重写了这些方法,现在它完美无缺.甚至通过网络流发送这些字节的目的也在起作用.

此外,正如Eric J.所建议的那样,我已经切换到使用数据流入ASCIIEnconding之间string和之间的变化.byte[]Stream

固定代码如下:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

现在一切都恰到好处,如下面的截图所示.这是第一名的预期产出.在服务器客户端可执行文件相互沟通和信息传播......它被序列化,妥善系列化.

图像显示正确的输出

Mar*_*ell 6

除了有关Encoding vs base-64的现有观察之外,请注意您尚未关闭deflate流.这很重要,因为压缩流缓冲:如果你不关闭,它可能不会写结束.对于短流,这可能意味着它什么都没写.

using(DeflateStream deflateStream = new DeflateStream(
    outputStream, CompressionMode.Compress))
{
    original.CopyTo(deflateStream);
}
return Convert.ToBase64String(outputStream.GetBuffer(), 0,
    (int)outputStream.Length);
Run Code Online (Sandbox Code Playgroud)