Question

for my current project I'm working with protobuf-net and I got some weird results.
I have a class that contains two properties:

[ProtoContract]
class MyClass{
    [ProtoMember(1)]
    public int ID { get; set; }
    [ProtoMember(2)]
    public string Description { get; set; }
}

If I set ID to 0 and enter a random Description and check the serialized byte[] afterwards, I don't get the expected result.

I would like to serialize the class with a length prefix.

I'm serializing the class like this:

var myclass = new MyClass()
{
    ID = 0, Description = "ThisIsAShortDescription"
};

using(var stream = new MemoryStream())
{
    Serializer.SerializeWithLengthPrefix<MyClass>(stream, myclass, PrefixStyle.Base128);

    Console.WriteLine(BitConverter.ToString(stream.GetBuffer());
}

I'm expecting something like this:

19 00 17 54 68 69 73 49 73 41 53 68 6f 72 74 44 65 73 63 72 69 70 74 69 6f 6e
19 -> length of the packet
00 -> ID
17 -> length of following string
rest -> string

Instead I'm getting: 19 12 17 54 68 69 73 49 73 41 53 68 6f 72 74 44 65 73 63 72 69 70 74 69 6f 6e

What is this 0x12 at the beginning? 0x00 != 0x12? I think that I've done anything right but is there maybe a silly bug in my code?

Was it helpful?

Solution

Hex 12 is the field header, and is binary 10010. The last 3 bits (010) is the wire type: length-prefixed. The remainder (10) is the field number (2). So the hex 12 is indicating that what follows is field 2, length-prefixed (in this case, a string). Field 1 has been omitted due to protobuf-net's implicit zero default behavior. You can force field 1 to be serialized in a number of ways if you need to.

OTHER TIPS

Here is sample code showing how to serialize.

It includes extension methods to serialize and deserialize any class using ProtoBuf.

To use, include the NuGet package protobuf-net (I used version 2.0.0.668).

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ProtoBuf;

namespace Protobuf_Net
{
    class Program
    {
        static void Main(string[] args)
        {
            MyMessage original = new MyMessage(42, "Bob");

            byte[] rawBytes = original.ProtoBufSerialize<MyMessage>();

            MyMessage deserialized = rawBytes.ProtoBufDeserialize<MyMessage>();

            Console.WriteLine("Num={0}", deserialized.Num);
            Console.WriteLine("Name={0}", deserialized.Name);
            Console.Write("[any key]");
            Console.ReadKey();
        }
    }
}

public static class ProtoBufExtensions
{
    // Intent: serializes any class to a byte[] array.
    public static byte[] ProtoBufSerialize<T>(this T message)
    {
        byte[] result;
        using (var stream = new MemoryStream())
        {
            Serializer.Serialize(stream, message);
            result = stream.ToArray();
        }
        return result;
    }

    // Intent: deserializes any class from a byte[] array.
    public static T ProtoBufDeserialize<T>(this byte[] bytes)
    {
        T result;
        using (var stream = new MemoryStream(bytes))
        {
            result = Serializer.Deserialize<T>(stream);
        }
        return result;
    }
}

[ProtoContract]
public struct MyMessage
{
public MyMessage(int num, string name)
{
    Num = num;
    Name = name;
}

[ProtoMember(1)]
public int Num { get; set; }

[ProtoMember(2)]
public string Name { get; set; }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top