I am facing some difficulty serializing an interface using CodeFirst in Protobuf-net.grpc. It is a DataMember within a DataContract. It works fine when I use it in a simple console application but when I try to use it in a different project with the same references, it doesn't serialize. I can see this error in the Visual studio output as well, when the AddCodeFirst is done on the gRPC Server :
Exception thrown: 'System.InvalidOperationException' in protobuf-net.dll
This is the code I have for the DataContract in both my project and the dummy application
using ProtoBuf;
namespace ProtoBufTesting.Prepare
{
[DataContract, ProtoContract]
public class ExtensionData
{
public ExtensionData() { }
public ExtensionData(
string extensionName,
string packageIdentifier,
IExtensionCertificateCollection collection)
{
this.ServiceName = extensionName;
this.PackageIdentifier = packageIdentifier;
this.CertificateCollection = collection;
}
[DataMember]
[ProtoMember(1)]
public string ServiceName
{
get; private set;
}
[DataMember]
[ProtoMember(4)]
public string PackageIdentifier
{
get; private set;
}
[DataMember]
[ProtoMember(5)]
public IExtensionCertificateCollection CertificateCollection { get; private set; }
}
}
This is the interface IExtensionCertificateCollection that has the ProtoContract decorator which works in my sample project.
namespace ProtoBufTesting
{
[ProtoContract]
public interface IExtensionCertificateCollection
{
IExtensionCertificate GetByThumbprint(string thumbprint);
IEnumerable<IExtensionCertificate> AllCertificates { get; }
}
}
This is the service contract that uses the ExtensionData DataContract
[ServiceContract(Namespace = "blah")]
public interface IRTC
{
[OperationContract]
ExtensionData PrepareExtension(PrepareExtensionInput input);
}
This is how I do the Code First setup if you see below. This works perfectly fine other than in the second project where I'm doing the same thing. I am really not sure how to go about debugging this. The reason I did a sample console application is to test if Interfaces serialize using ProtoContract decorators and they did successfully with just the ProtoContract decorator... But when I started using it in a larger project (same interface definition and data contract), it just doesn't seem to serialize the DataContract. It only serializes the DataContract when I remove that interface from the the Datamember. Any ideas how I should go about debugging this to find out what is causing this? I've been stuck on this for a few hours. Other than the InvalidOperationException, I don't see any other errors in the VS output.
Server server = new Server
{
Ports = { new ServerPort("localhost", ServerPort.PickUnused , ServerCredentials.Insecure) }
};
server.Services.AddCodeFirst(new RTC());
server.Start();
int port = server.Ports.Single().BoundPort;
Console.WriteLine("server listening on port " + port);
GrpcClientFactory.AllowUnencryptedHttp2 = true;
Channel channel = new Channel("localhost", port, ChannelCredentials.Insecure);
var rtc = channel.CreateGrpcService<IRTC>();
Update:
I figured out a different way to 'debug' this - using this method below. It parsed the schema of the object I'm trying to serialize. Putting a try catch with this specific object gave me an error atleast! "Tags must be positive integers". I found this issue and fixed it.
ProtoBuf.Meta.RuntimeTypeModel.Default.GetSchema(typeof(ExtensionData));
But after that error, I still keep getting the previous still and that doesn't seem to resolve. I'm running this under a Unit test method and it only shows a high level error like this during the AddCodeFirst - I added a TraceWriter in the AddCodeFirst and this is what it says -
[warning] Type cannot be serialized; ignoring: ExtensionData
[warning] Signature not recognized for PrepareExtension; method will not be bound
How do I go about investigating this further? This is linked to the previous error I still get:
Exception thrown: 'System.InvalidOperationException' in protobuf-net.dll
I was finally able to solve this. Lots of types associated to the interface (and others) that were not getting deserialized correctly. I didn't see this in any error log though which made it hard to find.. searching online /looking through codebehind for protobuf-grpc.. it looked like adding explicit registrations of all the types that are required to be deserialized by the interface is required, else it won't work.
I don't know if there is a better way to do this, but this was required just prior to the grPC AddCodeFirst else the service didn't ever register the methods without this being done first.
ProtoBuf.Meta.RuntimeTypeModel.Default.Add(typeof(IExtensionCertificateCollection), true).AddSubType(1, typeof(ExtensionCertificateCollection));
ProtoBuf.Meta.RuntimeTypeModel.Default.Add(typeof(IExtensionCertificateCollection), true).AddSubType(1, typeof(NewCollectionCerts));
server.Services.AddCodeFirst(new FakeRTC(), log: writelogs);