5

ソケットを使用してプロセス間通信を行うアプリケーションを作成しました。クライアントが作成したサーバーに接続し、シリアル化されたメッセージを送信すると、手順が開始されます。このメッセージは、SerializeWithLengthPrefix を使用して Protobuf-net を使用してシリアル化し、DeserializeWithLengthPrefix を使用して逆シリアル化します。クライアントは、メッセージを完全に逆シリアル化するサーバーにメッセージを送信しますが、サーバーからクライアントへの場合は同じではありません。

主なクラスは抽象クラスの BaseMessage です。

[Serializable, ProtoContract, ProtoInclude(5001, typeof(LogonMessage))]
abstract public class BaseMessage
{
    public BaseMessage()
    {

    }

    abstract public int MessageType { get; }
}

また、LogonMessage は BaseMessage クラスを実装しています。

[Serializable, ProtoContract]
public class LogonMessage : BaseMessage
{
    public LogonMessage()
    {

    }

    [ProtoMember(1)]
    public string Broker { get; set; }

    [ProtoMember(2)]
    public int ClientType { get; set; }

    public override int MessageType
    {
        get { return 1; }
    }
}

最初のハンドシェイクの後、クライアントは protobuf-net の助けを借りてシリアル化されたサービスを要求し、私の側のローカル サーバーは Web 上の別のサーバーからデータを要求することによってサービスを提供します。クライアントからサーバーへのこのメッセージ転送は問題なく行われます。

私のサーバーは Web サーバーからデータを受信すると、データをシリアル化し、データをクライアントに送信します。しかし今回、同じ手順を使用してクライアント側でデータをデシリアライズしようとすると、次の例外が発生します:「BaseMessage のパラメーターなしのコンストラクターが見つかりません」

次のコード行を使用して逆シリアル化します (ここで例外が発生します)。

BaseMessage baseMessage = Serializer.DeserializeWithLengthPrefix<BaseMessage>(networkStream, PrefixStyle.Base128);

そして、これがサーバー上でメッセージがシリアライズされた方法です。

Serializer.SerializeWithLengthPrefix(networkStream, baseMessage, PrefixStyle.Base128);

クライアントとサーバー間の接続の開始時に使用される NetworkStream はオブジェクトに格納され、そのオブジェクトはディクショナリに格納されます。ディクショナリ内のそのオブジェクトから同じ NetworkStream を選択し、それを使用して (サーバーから) シリアル化されたデータをクライアントに送信します。しかし、上記の問題が発生します。何か助けはありますか?

前もって感謝します...

4

5 に答える 5

4

これは、どの v2 リリースでも問題なく動作するはずです。2.0.0.480 は現在 NuGet で宣伝されているダウンロードですが、2.0.0.580 も利用できます。1.0.0.280 と 2.0.0.480 の両方を確認しましたが、どちらもこの症状を示していないため、別のビルドを使用していると推測されます。したがって、私のアドバイスは次のとおりです。これら2つのうちの1つ(または利用可能な場合はそれ以上)を使用していることを確認してください。

[Serializable]情報については、protobuf-netは必要ありませんが、害はありません。また、BaseMessageコンストラクターはおそらくprotected(型publicのコンストラクターでは実際には意味がありませんabstract) である必要があります。ただし、コンパイラが自動的にすべてを行うため、次のように簡略化できます。

[ProtoContract, ProtoInclude(5001, typeof(LogonMessage))]
abstract public class BaseMessage
{
    abstract public int MessageType { get; }
}


[ProtoContract]
public class LogonMessage : BaseMessage
{
    [ProtoMember(1)]
    public string Broker { get; set; }

    [ProtoMember(2)]
    public int ClientType { get; set; }

    public override int MessageType
    {
        get { return 1; }
    }
}

その他の考え:5001少し高いです。値の低いインクルード番号から効率が向上します。1思い浮かびます。それらは普遍的に一意である必要はありません。その型の中で一意であるだけです。

于 2012-09-13T11:54:25.813 に答える
3

追加するだけで、原点にシークされていない MemoryStream を逆シリアル化しようとしていて、クラスにパラメーターなしのコンストラクターがあったとしても、「BaseObject のパラメーターなしのコンストラクターが見つかりません」という例外が発生しました。

var tdp = new DerivedObject("Test");
using (var ms  = new MemoryStream())
{
    Serializer.Serialize(ms,tdp);
    //was missing this line
    ms.Seek(0, SeekOrigin.Begin);

    var tdp2 = Serializer.Deserialize<DerivedObject>(ms);
}
于 2015-03-11T16:06:17.467 に答える
2

これは質問に回答してから数年後であることは知っていますが、他の人にとって価値があるのは、抽象基本クラスを使用していて「{className のパラメーターなしのコンストラクターが見つかりませんでした」という問題に遭遇したことだけです。 }」メッセージですが、まったく間違った理由で...ばかげて、何も入っていないMemoryStreamからデシリアライズしていました(明らかに、当時は知らなかった)。イライラするほど愚かです。適切なエラー メッセージは次のとおり"id10t error - cannot deserialize nothing, dum dum!"です。

エラーメッセージは、コンストラクターの問題と抽象クラスの使用法を参照していたため、ライブラリを間違って使用していると思いました (つまり、クラス/メンバーをそれぞれの Proto* 属性で正しく装飾していないなど)。

要点は次のとおりです。このエラーメッセージを一粒の塩で受け取ってください-例外の根本的な原因は私のようなものである可能性があります。一歩下がって、protobuf-net API にアクセスしている場所の周りの可動部分を見て、壁に頭をぶつけてライブラリを探し回る前に、その周りで何か間抜けなことが起こっていないことを確認してください (つまり、この場合は、実際には正常に動作しています) 外部から。

エラーを再現するには?ノイズの多いコードの束が実際のバグから気をそらし、赤いニシンのエラーメッセージが表示されます...次のように:

[TestClass]
public class UnitTestJammieJawns
{
    [TestMethod]
    public void ProtobufAbstract_TestMethod()
    {
        var sub = new Sub() { AbstractInt = 234 , OtherInt32 = 987, SomeString = "qwer" };

        byte[] buffer = null;
        using (var ms = new MemoryStream())
        {
            ProtoBuf.Serializer.Serialize(ms, sub);  // works - hooray!
            buffer = ms.ToArray();  // we've got binary content, people!
        }

        Sub obj = null;
        using (var ms = new MemoryStream())  // woops... you forgot the provide the serialized object - should be: new MemoryStream(buffer) 
        {
            obj = ProtoBuf.Serializer.Deserialize<Sub>(ms);  // <- throws exception (this is good) with misleading message (this is not so good)
        }
    }
}

[ProtoContract]
[ProtoInclude(1, typeof(Sub))]
public abstract class Super
{
    public abstract int AbstractInt { get; set; }

    [ProtoMember(1)]
    public string SomeString { get; set; }
}

[ProtoContract]
public class Sub : Super
{
    [ProtoMember(2)]
    private int asdf;

    public override int AbstractInt
    {
        get
        {
            return asdf;
        }
        set
        {
            asdf = value;
        }
    }

    [ProtoMember(3)]
    public int OtherInt32 { get; set; }
}

これが私に引き起こした頭痛を他の誰かに救うことを願っています。

于 2015-07-31T20:57:45.627 に答える
-3

エラー

「パラメーターなしのコンストラクターが見つかりません」

プロトコル バッファ バイナリ ストリームがサブ クラス ([ProtoInclude] を介してリンク) ではなく、ちょうど開始ストリーム (バイナリ データの最初) にあるときに取得しました。

于 2020-06-04T13:27:40.730 に答える