2

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

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

当一个类实例被序列化并作为 blob 保存到数据库中时,我能够在从数据库中获取时反序列化它。但是,当我更换机器并尝试反序列化时,我得到了类型为 token 的 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;
    }

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

如果我做错了什么或需要处理更多事情,请给我一些启发。

谢谢

4

1 回答 1

2

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

现在,由于机器 A 和机器 B 具有相同的代码来对类型进行排序,并且由于代码相同,因此不会有额外的类型,所以我最终在两边都对类型进行了正确的排序,并得到了正确的反序列化对象。机器 A 序列化一个对象并存储在 Table 中的 blob 字段中,机器 B 从表中读取,DeSerialize 然后消费该对象。

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

应该有一种方法可以保留类型的顺序,如果检测到任何新类型,则应该在最后附加,这样现有类型的 MetaTypes 就不会受到干扰。

于 2013-12-28T15:29:28.540 回答