Note that there are some explanatory texts on larger screens.

plurals
  1. PODeserialize unknown type with protobuf-net
    primarykey
    data
    text
    <p>I have 2 networked apps that should send serialized protobuf-net messages to each other. I can serialize the objects and send them, however, <b>I cannot figure out how to deserialize the received bytes</b>.</p> <p>I tried to deserialize with this and it failed with a NullReferenceException.</p> <pre><code>// Where "ms" is a memorystream containing the serialized // byte array from the network. Messages.BaseMessage message = ProtoBuf.Serializer.Deserialize&lt;Messages.BaseMessage&gt;(ms); </code></pre> <p>I am passing a header before the serialized bytes that contains message type ID, which I can use in a giant switch statement to return the expected sublcass Type. With the block below, I receive the error: System.Reflection.TargetInvocationException ---> System.NullReferenceException.</p> <pre><code>//Where "ms" is a memorystream and "messageType" is a //Uint16. Type t = Messages.Helper.GetMessageType(messageType); System.Reflection.MethodInfo method = typeof(ProtoBuf.Serializer).GetMethod("Deserialize").MakeGenericMethod(t); message = method.Invoke(null, new object[] { ms }) as Messages.BaseMessage; </code></pre> <p>Here's the function I use to send a message over the network:</p> <pre><code>internal void Send(Messages.BaseMessage message){ using (System.IO.MemoryStream ms = new System.IO.MemoryStream()){ ProtoBuf.Serializer.Serialize(ms, message); byte[] messageTypeAndLength = new byte[4]; Buffer.BlockCopy(BitConverter.GetBytes(message.messageType), 0, messageTypeAndLength, 0, 2); Buffer.BlockCopy(BitConverter.GetBytes((UInt16)ms.Length), 0, messageTypeAndLength, 2, 2); this.networkStream.Write(messageTypeAndLength); this.networkStream.Write(ms.ToArray()); } } </code></pre> <p>This the class, with base class, I'm serializing:</p> <pre><code>[Serializable, ProtoContract, ProtoInclude(50, typeof(BeginRequest))] abstract internal class BaseMessage { [ProtoMember(1)] abstract public UInt16 messageType { get; } } [Serializable, ProtoContract] internal class BeginRequest : BaseMessage { [ProtoMember(1)] public override UInt16 messageType { get { return 1; } } } </code></pre> <p><hr> <b>Fixed</b> using Marc Gravell's suggestion. I removed the ProtoMember attribute from the readonly properties. Also switched to using SerializeWithLengthPrefix. Here's what I have now:</p> <pre><code>[Serializable, ProtoContract, ProtoInclude(50, typeof(BeginRequest))] abstract internal class BaseMessage { abstract public UInt16 messageType { get; } } [Serializable, ProtoContract] internal class BeginRequest : BaseMessage { public override UInt16 messageType { get { return 1; } } } </code></pre> <p>To receive an object:</p> <pre><code>//where "this.Ssl" is an SslStream. BaseMessage message = ProtoBuf.Serializer.DeserializeWithLengthPrefix&lt;BaseMessage&gt;( this.Ssl, ProtoBuf.PrefixStyle.Base128); </code></pre> <p>To send an object:</p> <pre><code>//where "this.Ssl" is an SslStream and "message" can be anything that // inherits from BaseMessage. ProtoBuf.Serializer.SerializeWithLengthPrefix&lt;BaseMessage&gt;( this.Ssl, message, ProtoBuf.PrefixStyle.Base128); </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload