ProtoBuf在反序列化过程中破坏了字节数组(添加了0)

问题描述 投票:5回答:2

我正在使用ProtoBuf.NET来序列化/反序列化某些类。我发现在反序列化时,我得到了一个损坏的byte [](额外的0)。在您询问之前,是的,我需要ProtoBuf API的* WithLengthPrefix()版本,因为ProtoBuf部分位于自定义流的开头:)

反正我知道

Original object is (JSON depiction):
{"ByteArray":"M+B6q+PXNuF8P5hl","ByteArray2":"DmErxVQ2y87IypSRcfxcWA==","K":2,"V
":1.0}

Protobuf: Raw Hex (42 bytes):
29-2A-20-0A-0C-33-E0-7A-AB-E3-D7-36-E1-7C-3F-98-65-12-10-0E-61-2B-C5-54-36-CB-CE
-C8-CA-94-91-71-FC-5C-58-08-02-15-00-00-80-3F

Regenerated object is (JSON depiction):
{"ByteArray":"AAAAAAAAAAAAAAAAM+B6q+PXNuF8P5hl","ByteArray2":"DmErxVQ2y87IypSRcf
xcWA==","K":2,"V":1.0}

AAA*A成员中的额外ByteArray基本上是base64中的十六进制0x00。

应用程序逻辑类似于

static void Main(string[] args)
{
    var parent = new Parent();
    parent.Init();

    Console.WriteLine("\nOriginal object is (JSON depiction):");
    Console.WriteLine(JsonConvert.SerializeObject(parent));

    using (var ms = new MemoryStream())
    {
        Serializer.SerializeWithLengthPrefix(ms, parent, PrefixStyle.Base128);
        byte[] bytes2 = ms.ToArray();
        var hex2 = BitConverter.ToString(bytes2);
        Console.WriteLine("\nProtobuf: Hex ({0} bytes):\n{1}", bytes2.Length, hex2);

        ms.Seek(0, SeekOrigin.Begin);
        var backFirst = Serializer.DeserializeWithLengthPrefix<Parent>(ms,PrefixStyle.Base128);

        Console.WriteLine("\nRegenerated object is (JSON depiction):");
        Console.WriteLine(JsonConvert.SerializeObject(backFirst));
    }
}

DTO类是

[DataContract]
[ProtoContract]
internal class Parent : Child
{
    [DataMember(Name = "ByteArray", Order = 10)]
    [ProtoMember(1)]
    public byte[] ByteArray { get; set; }

    [DataMember(Name = "ByteArray2", Order = 30, EmitDefaultValue = false)]
    [ProtoMember(2)]
    public byte[] ByteArray2 { get; set; }

    public Parent()
    {
        ByteArray = new byte[12];
    }

    internal void Init(bool bindRow = false)
    {
        base.Init();
        var rng = new RNGCryptoServiceProvider();
        rng.GetBytes(ByteArray);

        ByteArray2 = new byte[16];
        rng.GetBytes(ByteArray2);
    }
}

[DataContract]
[ProtoContract]
[ProtoInclude(5, typeof(Parent))]
public class Child
{
    [DataMember(Name = "K", Order = 100)]
    [ProtoMember(1)]
    public Int32 K { get; set; }

    [DataMember(Name = "V", Order = 110)]
    [ProtoMember(2)]
    public float V { get; set; }

    internal void Init()
    {
        K = 2;
        V = 1.0f;
    }
}

我确实看到,当我将ByteArray = new byte[12]Parent构造函数移到它的Init()方法中时,ProtoBuf可以正常工作。但是,我们有应用逻辑可防止在实际版本中出现这种情况(与您在上方看到的SO精简代码相对)。

我们是在做错什么还是ProtoBuf中的错误?

c# protocol-buffers protobuf-net
2个回答
4
投票

我们去:

public Parent()
{
    ByteArray = new byte[12];
}

注意:protobuf被设计为(由Google设计)可附加和可合并。附加/合并与“附加”同义(对于列表/数组等)。

两个选项(都可以通过属性):

  • 禁用构造函数:[ProtoContract(SkipConstructor = true)]
  • 禁用附加:[ProtoMember(1, OverwriteList = true)]

还有其他选择,但那些是我倾向于的选择。

您注意到数组初始化在实际代码中是不同的,但是:我无法评论看不到的代码。


0
投票

我面临着同样的问题,我的Bytestring数据实际上是我从服务器获取的XML数据,因此在我的应用程序中,我已经有一个XML Serialaizer,因此我决定使用它而不是引入一个新的serializer用于Photobuf并装饰我的所有模型,我发现此任务非常耗时。

这是我的功能,它将deserialize我的Bytestring

public SceneDTO ParseSceneAsyncFromByteString(ByteString byteStringData) {
    var serializer = new CustomXmlSerializer(typeof(SceneDTO), _timingManager);
    serializer.UnknownNode += OnUnknownNode;
    serializer.UnknownAttribute += OnUnknownAttribute;

    var ms = new MemoryStream(byteStringData.ToByteArray());
    var scene = (SceneDTO) serializer.Deserialize(ms);

    serializer.UnknownNode -= OnUnknownNode;
    serializer.UnknownAttribute -= OnUnknownAttribute;
    return scene;
}

我遵循此操作的另一个原因是,在使用Photobuf serializer之后出现以下错误。

源数据中的意外末端组;这通常意味着来源数据已损坏photobuf解串器

而且即使解决了这个问题,我的模型数据也始终为空,由于我已经有了一个可行的解决方案,因此我决定不花费很多时间来解决该问题。

© www.soinside.com 2019 - 2024. All rights reserved.