使用protobuf.net反序列化时的ArgumentException {token}

时间:2013-12-28 10:45:06

标签: c# .net serialization protobuf-net argumentexception

我使用protobuf-net进行序列化和反序列化。

我正在遵循的方法是创建RuntimeTypeModel并添加需要序列化或支持seralization的所有类型。添加所有类型后,我使用TypeModel.Compile()获得性能优势。

当一个类实例被序列化并保存为blob到数据库中时,我能够从数据库中获取时反序列化。但是,当我更改机器并尝试反序列化时,我在

获取类型标记的ArgumentException
   at ProtoBuf.ProtoReader.EndSubItem(SubItemToken token, ProtoReader reader) in c:\Dev\protobuf-net\protobuf-net\ProtoReader.cs:line 584
   at ProtoBuf.ProtoReader.ReadTypedObject(Object value, Int32 key, ProtoReader reader, Type type) in c:\Dev\protobuf-net\protobuf-net\ProtoReader.cs:line 567
   at ProtoBuf.ProtoReader.ReadObject(Object value, Int32 key, ProtoReader reader) in c:\Dev\protobuf-net\protobuf-net\ProtoReader.cs:line 543
   at proto_157(Object , ProtoReader )
   at ProtoBuf.Serializers.CompiledSerializer.ProtoBuf.Serializers.IProtoSerializer.Read(Object value, ProtoReader source) in c:\Dev\protobuf-net\protobuf-net\Serializers\CompiledSerializer.cs:line 57
   at ProtoBuf.Meta.RuntimeTypeModel.Deserialize(Int32 key, Object value, ProtoReader source) in c:\Dev\protobuf-net\protobuf-net\Meta\RuntimeTypeModel.cs:line 783
   at ProtoBuf.ProtoReader.ReadTypedObject(Object value, Int32 key, ProtoReader reader, Type type) in c:\Dev\protobuf-net\protobuf-net\ProtoReader.cs:line 556
   at ProtoBuf.ProtoReader.ReadObject(Object value, Int32 key, ProtoReader reader) in c:\Dev\protobuf-net\protobuf-net\ProtoReader.cs:line 543
   at proto_190(Object , ProtoReader )
   at ProtoBuf.Serializers.CompiledSerializer.ProtoBuf.Serializers.IProtoSerializer.Read(Object value, ProtoReader source) in c:\Dev\protobuf-net\protobuf-net\Serializers\CompiledSerializer.cs:line 57
   at ProtoBuf.Meta.RuntimeTypeModel.Deserialize(Int32 key, Object value, ProtoReader source) in c:\Dev\protobuf-net\protobuf-net\Meta\RuntimeTypeModel.cs:line 783
   at ProtoBuf.Meta.TypeModel.DeserializeCore(ProtoReader reader, Type type, Object value, Boolean noAutoCreate) in c:\Dev\protobuf-net\protobuf-net\Meta\TypeModel.cs:line 683
   at ProtoBuf.Meta.TypeModel.Deserialize(Stream source, Object value, Type type, SerializationContext context) in c:\Dev\protobuf-net\protobuf-net\Meta\TypeModel.cs:line 582
   at ProtoBuf.Meta.TypeModel.Deserialize(Stream source, Object value, Type type) in c:\Dev\protobuf-net\protobuf-net\Meta\TypeModel.cs:line 561

代码库是相同的,但是从我遇到此问题的另一台机器运行。

参与序列化的类非常简单

public class NetworkData
{

}

/// <summary>
/// Class for representing dashboard URL item
/// </summary>
public class DashboardURLItem : NetworkData
{
    /// <summary>
    /// Gets and Sets the URL
    /// </summary>
    public string URL { get; set; }

    /// <summary>
    /// Gets and Sets the Header for the URL Item
    /// </summary>
    public string Header { get; set; }
}

对于序列化,我使用以下代码

    public byte[] SerializeData(T piclObjectData)
    {
        try
        {
            using (MemoryStream loclStream = new MemoryStream())
            {
                NWTypeModel.Serialize(loclStream, piclObjectData);
                byte[] resultbuffer = new byte[loclStream.Length + 4]; // Those many bytes were generated in serialization + Message Length
                Array.Copy(BitConverter.GetBytes(resultbuffer.Length), resultbuffer, 4);
                Array.Copy(loclStream.GetBuffer(), 0, resultbuffer, 4, loclStream.Position);
                return resultbuffer;
            }
        }
        catch (Exception E)
        {
            Logger.WriteLog(ToString() + ": Exception while serializing - " + E.Message);
            throw;
        }
    }

反序列化代码

    public T DeSerializeData(byte[] piarBuffer)
    {
        try
        {
            using (MemoryStream loclStream = new MemoryStream())
            {
                loclStream.Seek(0, SeekOrigin.Begin);
                loclStream.Write(piarBuffer, 4, piarBuffer.Length - 4); // 4 Bytes for Message length
                loclStream.Seek(0, SeekOrigin.Begin);
                return (T)NWTypeModel.Deserialize(loclStream, null, f_GenericType);
            }
        }
        catch (Exception E)
        {
            Logger.WriteLog(ToString() + ": Exception while de-serializing - " + E.Message);
        }
        return null;
    }

序列化和反序列化在数据库的同一台机器上工作正常,但是当从另一台机器上的数据库获取值时,它无法反序列化。

如果我做错了什么或需要处理更多事情,请稍微说清楚。

由于

1 个答案:

答案 0 :(得分:2)

最后花了几个小时调试protobuf-net源代码后,我发现了问题。 Protobuf-net内部使用一个列表,并且不会对要添加的类型进行排序。因此,当我从机器A启动exe时,与机器B上的排序相比,使用反射的类型以不同的顺序添加。当代码库相同时,不知道反射是否应该发出相同的类型顺序。但是,我添加了一个SortedList来存储程序集中的类型,然后添加到RuntimeTypeModel。

现在,既然机器A和机器B都有相同的代码来排序类型,并且没有额外的类型,因为代码是相同的,我最终在两侧都有正确的类型排序并得到了正确的反序列化宾语。 Machine A序列化一个对象并存储在Table中的blob字段中,Machine B从表中读取DeSerializes然后使用该对象。

排序很重要,因为我将序列化数据保存在数据库中,然后反序列化。但是,如果将来添加更多类型,则订单将再次更改。我正在尝试为此提供一个简单的解决方案,以便在不破坏现有类型的序列化或反序列化的情况下添加未来的类型。

应该有一种方法可以保留类型的顺序,如果检测到任何新类型,那么应该在最后添加,以便不会干扰现有类型MetaType。