Reputation: 605
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
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
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
Reputation: 1062492
That usually means either:
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:
MercuryReply
class look like?Upvotes: 4