Serial serialization / deserialization of sections Protobuf-net

I checked, but didn't seem to be able to see how to directly serialize the class to an array of bytes and subsequently deserialize from the byte array using the protobuf-net implementation of Marc Gravell.

Edit: I changed the question and provided the code because the original question of how to serialize in byte [] without having to go through the stream is admittedly trivial. My apologies.

Updated question: Is there a way to not deal with generics and instead output the property type “MessageBody” through reflection when it is passed through the constructor? I suppose I can't serialize the type of an object, right? The current solution looks very cumbersome as I need to pass the MessageBody type every time I create a new message. Is there a smoother solution?

I came up with the following:

class Program { static void Main(string[] args) { Message<string> msg = new Message<string>("Producer", "Consumer", "Test Message"); byte[] byteArray = msg.Serialize(); Message<string> message = Message<string>.Deserialize(byteArray); Console.WriteLine("Output"); Console.WriteLine(message.From); Console.WriteLine(message.To); Console.WriteLine(message.MessageBody); Console.ReadLine(); } } [ProtoContract] public class Message<T> { [ProtoMember(1)] public string From { get; private set; } [ProtoMember(2)] public string To { get; private set; } [ProtoMember(3)] public T MessageBody { get; private set; } public Message() { } public Message(string from, string to, T messageBody) { this.From = from; this.To = to; this.MessageBody = messageBody; } public byte[] Serialize() { byte[] msgOut; using (var stream = new MemoryStream()) { Serializer.Serialize(stream, this); msgOut = stream.GetBuffer(); } return msgOut; } public static Message<T> Deserialize(byte[] message) { Message<T> msgOut; using (var stream = new MemoryStream(message)) { msgOut = Serializer.Deserialize<Message<T>>(stream); } return msgOut; } } 

What I like is something like:

Message newMsg = new message ("Producer", "Consumer", Foo); byte [] byteArray = newMsg.Serialize ();

and Message msg = Message.Deserialize (byteArray);

(where Deserialize is a static method and it always deserializes into an object of type Message and needs to know only which type deserializes the message body).

+8
c # serialization bytearray protocol-buffers protobuf-net
source share
2 answers

there are several different questions here, so I’ll answer what I see: if I missed something, just let me know.

First, as noted, a MemoryStream is the most common way to access bytes []. This is consistent with most serializers — for example, the XmlSerializer, BinaryFormatter, and DataContractSerializer also do not have “overload [] bytes”, but will accept a MemoryStream.

Generics: you do not need to use generics; v1 has a Serializer.NonGeneric that wraps this from you. In v2, the "core" is not shared and can be accessed through RuntimeTypeModel.Default; Of course Serializer and Serializer.NonGeneric continue to work.

In order to include the type: yes, the protobuf spec assumes that the receiver knows what type of data they return. A simple option here is to use a simple wrapper object as the “root” object with several typed properties for the data (only one of which is not null). Another option would be spring from the built-in support for inheritance via ProtoInclude (note: as an implementation detail, these two approaches are identical).

In your specific example, perhaps consider:

 [ProtoContract] [ProtoInclude(1, typeof(Message<Foo>))] .... More as needed [ProtoInclude(8, typeof(Message<Bar>))] public abstract class Message { } [ProtoContract] public class Message<T> : Message {  ... } 

Then just serialize with <Message> - the API will automatically create the correct type.

In recent builds, there is also DynamicType , which includes type data for you, for example:

 [ProtoContract] public class MyRoot { [ProtoMember(1, DynamicType=true)] public object Value { get; set; } } 

This will work for any value that contains an instance of a contract type (but not for primitives and ideally does not include inheritance).

+8
source share

The code published by OP will not work for me, the next little adaptation accepting on board a little more Mark Gravell suggestions. Inheritance from the message was necessary to prevent "circular inheritance is not allowed," and, as noted in the code comments below, GetBuffer did not work either.

Hoping this helps someone else, I spent several hours to get everything working ...

 [ProtoContract] public abstract class Message { public byte[] Serialize() { byte[] result; using (var stream = new MemoryStream()) { Serializer.Serialize(stream, this); result = stream.ToArray(); //GetBuffer was giving me a Protobuf.ProtoException of "Invalid field in source data: 0" when deserializing } return result; } } [ProtoContract] public class Message : Message { [ProtoMember(1)] public string From { get; private set; } [ProtoMember(2)] public string To { get; private set; } [ProtoMember(3)] public T MessageBody { get; private set; } public Message() { } public Message(string from, string to, T messageBody) { this.From = from; this.To = to; this.MessageBody = messageBody; } public static Message Deserialize(byte[] message) { Message result; using (var stream = new MemoryStream(message)) { result = Serializer.Deserialize>(stream); } return result; } } 
+3
source share

All Articles