Hi Marc,
I tried to send a new Pull Request but as my previous PR hasn't been merged yet, my new PR was added to the previous one instead of creating a new one.
Anyway the relevant commit is:
25ee825
Where I've added tests to test protobuf-net inheritence and compatibility with Google's protoc and grpc code-gen for C#.
There's a few issues, tested with these models:
[ProtoContract]
[ProtoInclude(10, typeof(Sub))]
[ProtoInclude(11, typeof(GenericBase<>))]
public abstract class Base
{
[ProtoMember(1)]
public string String { get; set; }
[ProtoMember(2)]
public Dictionary<string,string> StringDictionary { get; set; }
}
[ProtoContract]
public class Sub : Base
{
[ProtoMember(1)]
public long Long { get; set; }
}
[ProtoContract]
public class Poco
{
[ProtoMember(1)]
public short Short { get; set; }
}
[ProtoContract]
[ProtoInclude(20, typeof(SubGeneric))]
public class GenericBase<T> : Base
{
[ProtoMember(1)]
public T Result { get; set; }
}
[ProtoContract]
public class SubGeneric : GenericBase<Poco>
{
[ProtoMember(1)]
public int Int { get; set; }
}
The basic inheritance test works where you can Serialize/Deserialize the simple Sub example in protobuf-net, but it partially fails when trying to deserialize the SubGeneric Type where it fails to deserialize the Base Types properties:
var from = new SubGeneric {
Int = 1,
String = "Base",
StringDictionary = new Dictionary<string, string> {
{"A", "OK"}
},
Result = new Poco {
Short = 2
}
};
using var ms = new MemoryStream();
Serializer.Serialize(ms, from);
ms.Position = 0;
var to = Serializer.Deserialize<SubGeneric>(ms);
Assert.Equal(from.Result.Short, to.Result.Short);
Assert.Equal(from.Int, to.Int);
Assert.Equal(from.String, to.String); //FAIL to.String == null
Assert.Equal(from.StringDictionary["A"], to.StringDictionary["A"]); //FAIL to.StringDictionary == null
Protoc Inheritance Incompatibility
I've then taken the .proto generated from typeModel.GetSchema() schema to generate the protoc models using Google's protoc and grpc tools which whilst it generates all types does not provide anyway AFAICS to populate the base properties:
[Fact]
public void CanDeserializeInheritedTypesWithProtoc()
{
var from = new Sub {
Long = 1,
// Cannot populate inherited properties:
// String = "Base",
// StringDictionary = new Dictionary<string, string> {
// {"A", "OK"}
// }
};
using var ms = new MemoryStream();
from.WriteTo(ms);
ms.Position = 0;
var to = Sub.Parser.ParseFrom(ms);
Assert.Equal(from.Long, to.Long);
}
From the inheritence.proto we can see that the Base type has the container for all the sub types that inherits it, but I don't see how that's meant to work with gRPC in practice? as when you define a Service that sends a Sub or SubGeneric it only generates an API that lets you pass an instance of Sub in, not the Base type which contains all the Sub Type info:
rpc GetSub(Sub) returns (Sub) {}
Otherwise the test from protoc Sub -> protoc Sub is able to serialize its direct property, however it doesn't work when trying to deserialize protoc Sub -> protobuf.net Sub:
[Fact]
public void CanDeserializeProtocInheritedTypesWithProtobufNet()
{
var from = new Sub {
Long = 1,
// Cannot populate inherited properties:
// String = "Base",
// StringDictionary = new Dictionary<string, string> {
// {"A", "OK"}
// }
};
using var ms = new MemoryStream();
from.WriteTo(ms);
ms.Position = 0;
//throws System.InvalidOperationException : It was not possible to prepare a serializer for: ProtobufNet.Grpc.Test.Integration.Base
var to = Serializer.Deserialize<Integration.Sub>(ms);
Assert.Equal(from.Long, to.Long);
}
I'm assuming this scenario is meant to be compatible as it's required for protobuf-net.Grpc to work with protoc generated clients, but I'm not seeing where I'm doing inheritance wrong as from all relevant docs the Sub types are meant to be annotated on the Base type but this doesn't look like it translates well in protoc generated clients.
Hi Marc,
I tried to send a new Pull Request but as my previous PR hasn't been merged yet, my new PR was added to the previous one instead of creating a new one.
Anyway the relevant commit is:
25ee825
Where I've added tests to test protobuf-net inheritence and compatibility with Google's protoc and grpc code-gen for C#.
There's a few issues, tested with these models:
The basic inheritance test works where you can Serialize/Deserialize the simple
Subexample in protobuf-net, but it partially fails when trying to deserialize theSubGenericType where it fails to deserialize theBaseTypes properties:Protoc Inheritance Incompatibility
I've then taken the
.protogenerated fromtypeModel.GetSchema()schema to generate the protoc models using Google's protoc and grpc tools which whilst it generates all types does not provide anyway AFAICS to populate the base properties:From the
inheritence.protowe can see that theBasetype has the container for all the sub types that inherits it, but I don't see how that's meant to work with gRPC in practice? as when you define a Service that sends aSuborSubGenericit only generates an API that lets you pass an instance ofSubin, not theBasetype which contains all the Sub Type info:rpc GetSub(Sub) returns (Sub) {}Otherwise the test from protoc Sub -> protoc Sub is able to serialize its direct property, however it doesn't work when trying to deserialize protoc Sub -> protobuf.net Sub:
I'm assuming this scenario is meant to be compatible as it's required for protobuf-net.Grpc to work with protoc generated clients, but I'm not seeing where I'm doing inheritance wrong as from all relevant docs the Sub types are meant to be annotated on the
Basetype but this doesn't look like it translates well in protoc generated clients.