Tengo 2 aplicaciones en red que deben enviar mensajes protobuf-net serializados entre sí. Puedo serializar los objetos y enviarlos, sin embargo, No puedo entender cómo deserializar los bytes recibidos.Deserializar el tipo desconocido con protobuf-net
Intenté deserializar con esto y falló 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);
estoy pasando una cabecera antes de los bytes serializados que contiene el ID de tipo de mensaje, que puedo utilizar en una sentencia switch gigante para devolver el esperado Tipo sublcass. Con el bloque siguiente, recibo el error: 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;
Aquí es la función que utilizo para enviar un mensaje a través de la red:
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());
}
}
Este la clase, la clase base, estoy serializar:
[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; }
}
}
Se corrigió el usando la sugerencia de Marc Gravell. Eliminé el atributo ProtoMember de las propiedades de solo lectura. También cambió a usar SerializeWithLengthPrefix. Esto es lo que tengo ahora:
[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; }
}
}
Para recibir un objeto:
//where "this.Ssl" is an SslStream.
BaseMessage message =
ProtoBuf.Serializer.DeserializeWithLengthPrefix<BaseMessage>(
this.Ssl, ProtoBuf.PrefixStyle.Base128);
Para enviar un objeto:
//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);
me olvidó mencionar, estoy serialización en .NET 3.5 en Windows y deserializar en Mono 2.2 y estoy usando los archivos DLL-protobuf neta apropiadas en cada plataforma. –
Volveré para leer esto y publicar una respuesta en aproximadamente media hora ... tengo que salir corriendo en este momento, lo siento. Por cierto, el próximo lanzamiento tiene envolturas no genéricas integradas, todavía en mi computadora portátil en este momento. –
por cierto - Estoy trabajando en la fusión de mi copia local, por lo que puedo confirmar los cambios para que sea más fácil. Tengo una falla de prueba excepcional, pero eso cubre el nuevo código, por lo que estoy contento de confirmarlo (marcado como ignorado) si ayuda. –