Ho 2 app collegate in rete che dovrebbero inviare messaggi protobuf-net serializzati tra loro. Posso serializzare gli oggetti e inviarli, tuttavia, Non riesco a capire come deserializzare i byte ricevuti.Deserializzare il tipo sconosciuto con protobuf-net
Ho provato a deserializzare con questo e non è riuscito con una NullReferenceException.
// Where "ms" is a memorystream containing the serialized
// byte array from the network.
Messages.BaseMessage message =
ProtoBuf.Serializer.Deserialize<Messages.BaseMessage>(ms);
sto passando un colpo di testa prima che i byte serializzati che contiene il tipo di messaggio ID, che posso utilizzare in un'istruzione switch gigante per restituire il tipo sublcass previsto. Con il blocco sottostante, ricevo l'errore: System.Reflection.TargetInvocationException ---> System.NullReferenceException.
//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;
Ecco la funzione che uso per inviare un messaggio attraverso la rete:
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());
}
}
Questa classe, con classe di base, sto serializzazione:
[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; }
}
}
Fixato usando il suggerimento di Marc Gravell. Ho rimosso l'attributo ProtoMember dalle proprietà di sola lettura. Passa anche a usare SerializeWithLengthPrefix. Ecco quello che ho adesso:
[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; }
}
}
Per ricevere un oggetto:
//where "this.Ssl" is an SslStream.
BaseMessage message =
ProtoBuf.Serializer.DeserializeWithLengthPrefix<BaseMessage>(
this.Ssl, ProtoBuf.PrefixStyle.Base128);
Per inviare un oggetto:
//where "this.Ssl" is an SslStream and "message" can be anything that
// inherits from BaseMessage.
ProtoBuf.Serializer.SerializeWithLengthPrefix<BaseMessage>(
this.Ssl, message, ProtoBuf.PrefixStyle.Base128);
ho dimenticato di dire, sto serializzazione in .NET 3.5 su Windows e deserializzazione in Mono 2.2 e sto usando le DLL protobuf-net appropriate su ogni piattaforma. –
Tornerò a leggere questo e posta una risposta tra circa mezz'ora ... devo correre in questo momento, mi dispiace. BTW - la prossima versione ha wrapper non generici integrati - ancora sul mio portatile al momento, però. –
btw - Sto lavorando per unire la mia copia locale, così posso confermare le modifiche per renderlo più semplice. Ho un eccezionale test fallito, ma quello riguarda il nuovo codice, quindi sono contento di eseguirlo (contrassegnato come ignorato) se aiuta. –