2

シリアライゼーションとデシリアライゼーションにprotobuf-netを使用していました。

私が従った方法は、RuntimeTypeModel を作成し、シリアル化する必要がある、またはシリアル化をサポートする必要があるすべての型を追加することです。すべてのタイプを追加したら、パフォーマンス上の利点のために 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;
    }

シリアル化と逆シリアル化はデータベースの同じマシンで正常に機能していましたが、別のマシンでデータベースから値を取得すると、逆シリアル化できません。

私が何か間違ったことをしている場合や、さらに何かを処理する必要がある場合は、光を投げてください.

ありがとう

4

1 に答える 1

2

最後に、protobuf-net ソース コードのデバッグに何時間も費やした後、問題を発見しました。Protobuf-net は内部的にリストを使用し、追加されるタイプの並べ替えはありません。そのため、マシン A から exe を起動すると、マシン B での順序とは異なる順序でリフレクションを使用する型が追加されていました。ただし、型をアセンブリに格納するために SortedList を追加してから、RuntimeTypeModel に追加しました。

ここで、マシン A とマシン B の両方に型を並べ替えるための同じコードがあり、コードが同じであるため余分な型は存在しないため、両側で型の適切な順序付けが行われ、適切な逆シリアル化されたオブジェクトが得られました。マシン A はオブジェクトをシリアル化し、テーブルの blob フィールドに格納します。マシン B はテーブルから読み取り、オブジェクトをシリアル化解除してから使用します。

シリアル化されたデータをデータベースに保存してから逆シリアル化するため、順序付けは重要です。ただし、将来さらにタイプが追加された場合、順序は再び変更されます。既存の型のシリアル化または逆シリアル化を壊すことなく将来の型を追加できるように、これに対する絶対確実な解決策を試みています。

型の順序を保持し、新しい型が検出された場合は最後に追加して、既存の型 MetaType が乱されないようにする方法が必要です。

于 2013-12-28T15:29:28.540 に答える