views:

249

answers:

1

I have a working java client that is communicating with Google, through ProtoBuf serialized messages. I am currently trying to translate that client into C#.

I have a .proto file where the parameter appId is an optional string. Its default value in the C# representation as generated by the protobuf-net library is an empty string, just as it is in the java representation of the same file.

message AppsRequest {
  optional AppType appType = 1;
  optional string query = 2;
  optional string categoryId = 3;
  optional string appId = 4;
  optional bool withExtendedInfo = 6;
}

I find that when I explicitly set appId to "" in the java client, the client stops working (403 Bad Request from Google). When I explicitly set appId to null in the java client, everything works, but only because hasAppId is being set to false (I'm uncertain as to how that affects the serialization).

In the C# client, I always get 403 responses. I don't see any logic behind the distinction between not setting a value, and setting the default value, that seems to make all the difference in the java client. Since the output is always a binary stream, I am not sure if the successful java messages are being serialized with an empty string, or not serialized at all.

In the C# client, I've tried setting IsRequired to true on the ProtoMember attribute, to force them to serialize, and I've tried setting the default value to null, and explicitly set "", so I'm quite sure I've tried some configuration where the value is being serialized. I've also played around with ProtoBuf.ProtoIgnore and at some point, removing the appId parameter altogether, but I haven't been able to avoid the 403 errors in C#.

I've tried manually copying the serialized string from java, and that resolved my issues, so I'm certain that the rest of the HTTP Request is working, and the error can be traced to the serialized object.

My serialization is simply this:

var clone = ProtoBuf.Serializer.DeepClone(request);

MemoryStream ms = new MemoryStream(2000);
ProtoBuf.Serializer.Serialize(ms, clone);

var bytearr = ms.ToArray();
string encodedData = Convert.ToBase64String(bytearr);

I'll admit to not being quite sure about what DeepClone does. I've tried both with and without it...

+1  A: 

It sounds like we want to force it to be excluded; for a first thing to try, you could try using the "detectmissing" option in the code-generation. This is possible from the IDE and command-line, but differently (let me know which you are using and I'll add more).

Another similar option is to add (in a partial class) a bool {memberName}Specified {get;set;}. There is an existing open report of an oddity involving default empty strings, that I am looking at.

Marc Gravell
@Marc Gravell: Cheers for the quick response. I generated the code from command line. The `*Specified` property seems to have no effect on the outcome, regardless of whether I set it to `true` or `false`. Same thing goes for the `ShouldSerialize*` method, as suggested here: http://stackoverflow.com/questions/1379332/protobuf-net-not-serializing-zero
David Hedlund
I've found a piece of code in the java serializer that checks `if (hasAppId()) { output.writeString(4, getAppId()); }` so it does indeed appear that completely exclude it from the serialized output is what i want to do.
David Hedlund
@David Hedlund OK; I have your example - I'll see what I can do with it. For info, do you have a simple data example with the java output, so I can confirm the result?
Marc Gravell
@Mark Gravell: To provide you with some sample data, I created some simple objects, and compared the results. Then I noticed I was wrong about where the discrepancies appeared. I was thrown off before, by the fact that `""` was the default value, and that explicitly setting `""` caused the same error in Java. Here's the real deal: Setting `""` in java causes it to serialize, which gives me the 403. Setting `""` in C# never serialized at all, but *another* error kept giving me the 403. In C#, it was another value all along, that defaulted to `0` and was as such *not* serialized,
David Hedlund
...when it should be. I solved that by making it a required field. I'm accepting your answer as that together with the discussion that ensued lead me to the solution, and also, because the `*Specified { get; set; }` hint that I totally did'nt know about. Thanks heaps for your time, tho (and for a great library)
David Hedlund