Forgive, in advance, any ignorance regarding protobuffers or Go, as both of these technologies are relatively new to me.
We've been using protobuffers and protobuf-net in production for a little while. We use Redis as a message queue between systems, and everything that reads or writes to Redis uses the exact same models (a shared library) and protobuf-net to serialize and deserialize. Now, however, we want to push things into Redis from a system written in Go. My problem is that the Go-written protobuffer data is not able to be deserialized in my .NET application with protobuf-net
See the following small example for my problem.
I am using protoc version 2.6.1 for the Golang approach and protobuf-net version 2.0.0.668 for .NET
[ProtoContract]
[ProtoInclude(3, typeof(SomeDerivedClass))]
public abstract class BaseClass
{
[ProtoMember(1)]
public Int32 Foo { get; set; }
}
[ProtoContract]
public class SomeDerivedClass : BaseClass
{
[ProtoMember(2)]
public String Bar { get; set; }
}
Using Serializer.GetProto<SomeDerivedClass>();
yields the following .proto file:
message BaseClass {
optional int32 Foo = 1 [default = 0];
// the following represent sub-types; at most 1 should have a value
optional SomeDerivedClass SomeDerivedClass = 3;
}
message SomeDerivedClass {
optional string Bar = 2;
}
Which, using protogen, yielded the following .go file: https://gist.github.com/cjqed/408dd9fd11e935239f36
Then,
derived := &SomeDerivedClass{
Bar: proto.String("h"),
}
baseClass := &BaseClass{
SomeDerivedClass: derived,
Foo: proto.Int32(13),
}
data, err := proto.Marshal(baseClass)
if err != nil {
panic(err)
}
When deserialized with protobuf-net, results in
Result: ProtoException, No parameterless constructor found for BaseClass
...Unless I make BaseClass non-abstract. Which, although possible, is not really a good solution.
Finally, I made the exact same object in protobuf-net and in Go (both on the same machine, mind you), and these are the bytes for each:
(Code in protobuf-net to serialize)
var obj = new SomeDerivedClass
{
Bar = "h",
Foo = 13
};
byte[] data;
using (var memoryStream = new MemoryStream())
{
Serializer.Serialize(memoryStream, obj);
data = memoryStream.ToArray();
}
Protobuf-net:26, 3, 18, 1, 104, 8, 13
With github.com/golang/protobuf/proto:8, 13, 26, 3, 18, 1, 104
Note the last two bytes in protobuf-net are the first two in golang.
So, am I doing something wrong, or is there a bug in one of the two protobuffer libraries? Or maybe in the go protogen?