C# ProtoBuf网络错误消息;源数据中的字段无效:0“;

C# ProtoBuf网络错误消息;源数据中的字段无效:0“;,c#,serialization,deserialization,protobuf-net,C#,Serialization,Deserialization,Protobuf Net,我成功序列化了以下类的实例,但当我在收到以下错误消息后立即尝试反序列化时:“源数据中的字段无效:0” 我不知道它指的是什么,因为我发现下面的类是直截了当的。我刚刚将ProtobufNet版本更新为2.00.614(运行时版本:2.0.50727) 你知道我是否忽略了一些琐碎的事情吗 [ProtoContract] public class TimeSeriesProperties { [ProtoMember(1)] public string TimeSeriesName {

我成功序列化了以下类的实例,但当我在收到以下错误消息后立即尝试反序列化时:
“源数据中的字段无效:0”

我不知道它指的是什么,因为我发现下面的类是直截了当的。我刚刚将ProtobufNet版本更新为2.00.614(运行时版本:2.0.50727)

你知道我是否忽略了一些琐碎的事情吗

[ProtoContract]
public class TimeSeriesProperties 
{
    [ProtoMember(1)]
    public string TimeSeriesName { get; private set; }
    [ProtoMember(2)]
    public string FileName { get; private set; }
    [ProtoMember(3)]
    public string TemplateName { get; private set; }
    [ProtoMember(4)]
    public int PacketLength { get; private set; }
    [ProtoMember(5)]
    public long FileSizeBytes { get; set; }
    [ProtoMember(6)]
    public long NumberRecords { get; set; }
    [ProtoMember(7)]
    public DateTime DateTimeStart { get; set; }
    [ProtoMember(8)]
    public DateTime DateTimeEnd { get; set; }

    public TimeSeriesProperties()
    {

    }

    public TimeSeriesProperties(string timeSeriesName, string fileName, string templateName, int PacketLength)
    {
        this.TimeSeriesName = timeSeriesName;
        this.FileName = fileName;
        this.TemplateName = templateName;
        this.PacketLength = PacketLength;
    }

}

public static byte[] Serialize_ProtoBuf<T>(T serializeThis)
    {
        using (var stream = new MemoryStream())
        {
            ProtoBuf.Serializer.Serialize<T>(stream, serializeThis);
            return stream.GetBuffer();
        }
    }

    public static T Deserialize_ProtoBuf<T>(byte[] byteArray)
    {
        using (var stream = new MemoryStream(byteArray))
        {
            return ProtoBuf.Serializer.Deserialize<T>(stream);
        }
    }
[协议]
公共类时间体验属性
{
[原成员(1)]
公共字符串TimeSeriesName{get;private set;}
[原成员(2)]
公共字符串文件名{get;private set;}
[原成员(3)]
公共字符串TemplateName{get;private set;}
[原成员(4)]
public int PacketLength{get;private set;}
[原成员(5)]
公共长文件大小字节{get;set;}
[原成员(6)]
公共长号码记录{get;set;}
[原成员(7)]
公共日期时间日期时间开始{get;set;}
[原成员(8)]
公共日期时间日期时间结束{get;set;}
公共时间体验物业()
{
}
公共TimeSeriesProperties(字符串timeSeriesName、字符串文件名、字符串模板名、int PacketLength)
{
this.TimeSeriesName=TimeSeriesName;
this.FileName=文件名;
this.TemplateName=TemplateName;
this.PacketLength=PacketLength;
}
}
公共静态字节[]Serialize_ProtoBuf(T serializeThis)
{
使用(var stream=new MemoryStream())
{
ProtoBuf.Serializer.Serialize(流,serializeThis);
返回stream.GetBuffer();
}
}
公共静态T反序列化_协议(字节[]byteArray)
{
使用(var流=新内存流(byteArray))
{
返回ProtoBuf.Serializer.Deserialize(流);
}
}

我所看到的最常见的原因就是在
内存流上不正确地使用
GetBuffer()
。当我添加我的评论时,这已经是我的直觉了,但你已经证实了这一点:

using (var stream = new MemoryStream())
{
    ProtoBuf.Serializer.Serialize<T>(stream, serializeThis);
    return stream.GetBuffer();
}

这几乎总是意味着您过度读取了写入的数据,通常是由于错误处理
内存流
——与protobuf net无关;请显示执行序列化/反序列化测试的代码好吗?(理想情况下,添加一条@marc注释,这样我就知道要回来看看了)@marcgravel添加了这两种方法;规范的一个特点是,最外层的消息不知道自己的长度——这使得片段可以通过串联进行合并。因此,默认情况下,它读取到流的末尾(尽管对于某些
n
,大多数实现包括读取
n
字节的机制)。在每个字段的末尾,它需要另一个字段头或EOF。0永远不是有效的字段标头,因此尾随的零将中断反序列化程序。顺便说一句,每次写入的数据量只是:
stream.Length
,完全取决于上下文;在您所展示的场景中(对于大多数
等),长度是微不足道的,而整个过程都是通过
ToArray()
或受限读取来固定的。对于某些实现(例如
网络流
发送多条消息),
[Serialize | Deserialize]With LengthPrefix
是您的朋友。我不知道你为什么不知道序列化后的长度。你能详细说明一下吗?如果这是文件开头的标题,则带有LengthPrefix的
*应该可以正常工作。标记为已应答。对我来说,关键是“WithLengthPrefix”问题。我可以发誓,在我升级到当前的ProtoBuf网络版本后,我的代码就坏了。我可以向您保证,我序列化为大小为256的字节数组,即使实际序列化对象的长度仅为146,我通过传入10000字节数组进行反序列化,其中序列化对象仅占用前146个字节。它成功了,我绝对相信这一点。我不知道发生了什么变化,但我知道我的代码不安全,因为序列化对象没有以大小作为前缀。如果您使用的是新的存档,则此解决方案有效。如果我们已经使用GetBuffer()写出了归档文件,但我们不再知道归档文件的大小,那么有没有办法解决此问题?@Etienne您可以使用reader API检查下一个字段头何时为零,这从来都不是合法的-只有在
MemoryStream
以前没有用于其他随机对象时才有效(即,未使用的空间是否全部为零?)。见鬼,您可能只是删除了所有的尾随零-有一个边缘的情况下,有合法的尾随零,但这比挂钩阅读器API容易。你在这里说的是什么数量?10? 1000? 1000000?@Marc,我最终删除了尾随的零,这对我很有效。这可能不是最理想的解决方案,但在我的情况下,这将是如此不频繁地执行,这其实并不重要。我希望图书馆能有一些冷静的方法来处理这个问题,但我错了。
using (var stream = new MemoryStream())
{
    ProtoBuf.Serializer.Serialize<T>(stream, serializeThis);
    return stream.ToArray();
}