CommunistPancake
CommunistPancake

Reputation: 605

Invalid wire-type error in protobuf.net on a new MemoryStream

I'm trying to parse a protobuf message received from an external service. I know that this data is a valid protobuf message, and I know I'm not accidentally mangling it before I send it to the deserializer. Here's my code:

public static T DeserializeFromBytes<T>(byte[] encoded)
{
    MemoryStream stream = new MemoryStream(encoded);
    stream.SetLength(encoded.Length);
    stream.Capacity = encoded.Length;
    T decoded = (T)Serializer.Deserialize<T>(stream);
    stream.Close();
    return decoded;
}

and I'm calling this method like this:

MercuryReply header = ProtobufUtils.DeserializeFromBytes<MercuryReply>(Convert.FromBase64String(metadata[0]));

metadata[0] is a base64 string that includes a protobuf message. A sample looks something like this:

CjRobTovL21ldGFkYXRhL2FsYnVtL2M1MzU3MTA0M2U4ODQ3YjRhODc1YzVlNmZiNmNiZTdmEhp2bmQuc3BvdGlmeS9tZXRhZGF0YS1hbGJ1bSCQAzIYCgpNRC1WZXJzaW9uEgoxMzcwMzc5NTA1Mg8KBk1DLVRUTBIFNjk2MDQyGQoPTUMtQ2FjaGUtUG9saWN5EgZwdWJsaWMyDwoHTUMtRVRhZxIELD8q+Q==

Now, when I run the program, I get an Invalid wire-type error when deserializing. I can't see any reason why this would be happening. Is there something obvious here that I missed?

Upvotes: 3

Views: 23850

Answers (3)

Haney
Haney

Reputation: 34742

EDIT: as Marc Gravell points out in the comments, I'm on the wrong track. Please disregard my answer but I'm leaving it since the comment discussion is valuable.

protobuf-net is not the same thing as protobuf, and does not adhere to the algorithm in a uniform, cross-platform compatible way. protobuf-net is a .NET contract based serializer that happens to use protobuf, but does not implement protobuf "to spec" for the purposes of interoperability. For example: protobuf-net is aware of the .NET types, whereas Google's protobuf is not aware of .NET types. See this links for more:

http://code.google.com/p/protobuf-net/wiki/GettingStarted

Upvotes: 1

keemsisi
keemsisi

Reputation: 419

In my own case, using postman: The proto was updated in the backend code, but the postman still uses the old proto file and that was causing the error.

using the latest proto file from the postman solved the issue for me.

Upvotes: 1

Marc Gravell
Marc Gravell

Reputation: 1062492

That usually means either:

  • the binary is not valid (people make a mess of binary all the time; your use of base-64 is perfectly fine, though, if it needs to be stored/transferred as a string)
  • there is a mismatch in the data (for example, field 2 is varint in the data, but is a string in the type)

Based on you binary, I've pieced together that MercuryReply might look something like:

[ProtoContract]
public class MercuryReply
{
    [ProtoMember(1)]
    public string Location { get; set; }
    [ProtoMember(2)]
    public string ContentType { get; set; }
    [ProtoMember(4)]
    public int ResponseStatus { get; set; }
    [ProtoMember(6)]
    public Dictionary<string, string> Headers { get { return headers; } }
    private readonly Dictionary<string, string> headers
        = new Dictionary<string, string>();
}

(the names here are pure guesswork based on what the data looks like; protobuf does not transmit names - only the numeric keys, i.e. 1/2/4/6 in this example)

which works fine when tested with:

static void Main()
{
    var encoded = Convert.FromBase64String("CjRobTovL21ldGFkYXRhL2FsYnVtL2M1MzU3MTA0M2U4ODQ3YjRhODc1YzVlNmZiNmNiZTdmEhp2bmQuc3BvdGlmeS9tZXRhZGF0YS1hbGJ1bSCQAzIYCgpNRC1WZXJzaW9uEgoxMzcwMzc5NTA1Mg8KBk1DLVRUTBIFNjk2MDQyGQoPTUMtQ2FjaGUtUG9saWN5EgZwdWJsaWMyDwoHTUMtRVRhZxIELD8q+Q==");

    MercuryReply header = ProtobufUtils.DeserializeFromBytes<MercuryReply>(encoded);

}

(using your DeserializeFromBytes method)

So: if that isn't working for you, the important two questions are:

  • is that the actual base-64 from your real code at runtime? or is that just what you think it should be in theory?
  • what does your MercuryReply class look like?

Upvotes: 4

Related Questions