简体   繁体   中英

Invalid Wire Type Exception on Protobuf-net Deserialize with Nested Data (C++ to C#)

I've been given a C++ application (a built executable and source code that doesn't build right now) that uses generated proto classes to send protobuf messages. I took the same.proto files it used to generate its classes, and I generated associated classes in a C# app. The intent is to be able to receive and send messages between these apps, using protobuf-net on the C# side. Note that both are using the proto2 format.

Messages with only simple type (eg int) members can be serialized and deserialized successfully. However, there seems to be an issue deserializing messages with nested message types into my C# application, eg

message Outer {
    optional Inner = 1;
}

message Inner {
    optional float f = 1;
}

A received message of type "Outer" will fail to deserialize in C# via:

Serializer.Deserialize<T>(new MemoryStream(msg)); // msg is a byte[]

giving an "Invalid Wire Type Exception." I followed the link here , but having looked at those answers, I didn't find anything immediately obvious relating to my situation. I'm 95% sure the source and destination generated classes are the same, the data isn't corrupt, and I'm deserializing to the correct type.

Can I correctly deserialize such nested types? Is there a compatibility issue with the way the classes were generated (and how it serializes) in the C++ app vs the C# app using protobuf-net?

Here is an example project (made in VS 2019 for .NET Core 3.1) which will reproduce the issue.

My incoming data had about 50 extra bytes of "stuff" I wasn't expecting (ie not the message header), which didn't adhere to the defined message format, so the data was essentially corrupt. It was hard to tell this from looking at a stream of bytes; what gave it away was the difference in length of a message that I serialized on the C# side compared to the bytes I read from wireshark of a message coming in. I then looked at those bytes and found equivalent bytes to my serialized message a little ways in.

Why there is extra "stuff" in the incoming message is another matter, but this is an implementation detail, so I'll consider this question closed.

If it helps anyone in a similar situation, I made a little test loop to keep trying to deserialize byte-by-byte until it works (could be improved but works for now):

var rawBytes = msg.GetBytes(); // The raw incoming message
bool success = false;
OuterMsgType outer;
while (!success)
{
    try
    {
        rawBytes = rawBytes.Skip(1).ToArray();
        outer = ProtoBuf.Serializer.Deserialize<OuterMsgType>(new MemoryStream(rawBytes));
        if (outer?.InnerMsg != null)
             success = true;
    }
    catch (Exception e)
    {
        // Wire type exception: Ignore it, don't care
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM