Messages are serialized with a length delimiter, so changing the content produces a mismatch and invalid message.
Your schema has no affected repeated fields, so appending a delta should work. I've never used the C# API, but here is some hopefully understandable pseudo code: var delta = Request.newInstance(); delta.getMutableMeta().getMutableCutOffTime() .setValue(value) .setScale(TimeSpanScale.MINMAX) byte[] output = append(unmodifiedInputBytes, delta.toByteArray()); If the server expects a length delimiter you'd need to update it to the new combined length. - Florian On Wednesday, September 20, 2023 at 11:03:46 AM UTC+2 Joan Balagueró wrote: > Hi Florian, > > Thanks for your quick response. I'm stuck on this. > > 1) It's not working. When I send the protobuf to the backend server (it's > not our api nor server) using the first method, I get a right response. But > using the second method I receive this error: > ProtoBuf.ProtoException: Invalid wire-type; this usually means you have > over-written a file without truncating or setting the length; see > https://stackoverflow.com/q/2152978/23354 > at ProtoBuf.ProtoReader.StartSubItem(ProtoReader reader) in > C:\code\protobuf-net\src\protobuf-net\ProtoReader.cs:line 637 > at ProtoBuf.ProtoReader.ReadTypedObject(Object value, Int32 key, > ProtoReader reader, Type type) in > C:\code\protobuf-net\src\protobuf-net\ProtoReader.cs:line 584 > at proto_40(Object , ProtoReader ) > at ProtoBuf.Meta.TypeModel.DeserializeCore(ProtoReader reader, Type > type, Object value, Boolean noAutoCreate) in > C:\code\protobuf-net\src\protobuf-net\Meta\TypeModel.cs:line 722 > at ProtoBuf.Meta.TypeModel.Deserialize(Stream source, Object value, > Type type, SerializationContext context) in > C:\code\protobuf-net\src\protobuf-net\Meta\TypeModel.cs:line 599 > at > WebBeds.Connect.AspNetCore.Formatters.ProtobufInputFormatter.ReadRequestBodyAsync(InputFormatterContext > > context) > at > Microsoft.AspNetCore.Mvc.Formatters.InputFormatter.ReadAsync(InputFormatterContext > > context) > at > Microsoft.AspNetCore.Mvc.ModelBinding.Binders.BodyModelBinder.BindModelAsync(ModelBindingContext > > bindingContext) > at > Microsoft.AspNetCore.Mvc.ModelBinding.ParameterBinder.BindModelAsync(ActionContext > > actionContext, IModelBinder modelBinder, IValueProvider valueProvider, > ParameterDescriptor parameter, ModelMetadata metadata, Object value, Object > container) > at > Microsoft.AspNetCore.Mvc.Controllers.ControllerBinderDelegateProvider.<>c__DisplayClass0_0.<<CreateBinderDelegate>g__Bind|0>d.MoveNext() > --- End of stack trace from previous location --- > at > Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker > > invoker, Task lastTask, State next, Scope scope, Object state, Boolean > isCompleted) > at > Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextExceptionFilterAsync>g__Awaited|26_0(ResourceInvoker > > invoker, Task lastTask, State next, Scope scope, Object state, Boolean > isCompleted > > > 2) This is the proto: > > The request with the 'Meta' element: > > message Request { > Meta Meta = 1; > repeated int32 Hotels = 2 [packed = false]; > Country Market = 3; > repeated Room Rooms = 4; > .bcl.DateTime CheckIn = 5; > .bcl.DateTime CheckOut = 6; > OptionalCriteria OptionalCriteria = 7; > } > > The 'Meta' element that contains the 'CutOffTime' that we want to modify: > > message Meta { > int32 Client = 1; > int32 Brand = 2; > bool UseCache = 3; > .bcl.TimeSpan CutOffTime = 4; > bool B2C = 5; > Language Language = 6; > Currency Currency = 7; > bool IncludeProviderAuditData = 8; > SalesChannel SalesChannel = 9; > string AgentId = 10; > } > > The 'CutOffTime': > > message TimeSpan { > sint64 value = 1; // the size of the timespan (in units of the selected > scale) > TimeSpanScale scale = 2; // the scale of the timespan [default = DAYS] > enum TimeSpanScale { > DAYS = 0; > HOURS = 1; > MINUTES = 2; > SECONDS = 3; > MILLISECONDS = 4; > TICKS = 5; > > MINMAX = 15; // dubious > } > } > > Thanks, > > Joan. > > > > > > > On Wednesday, September 20, 2023 at 10:40:08 AM UTC+2 Florian Enner wrote: > >> 1) A "varint" is a "variable length integer". When you replace a large >> number with a small one, it's entirely possible to lose some bytes and >> still be valid. You need to check the actual output. >> >> 2) Can you provide the proto definition of the field you want to modify? >> Scalar fields get set to the last encountered value, so the easiest option >> may be to copy the original bytes and append a delta containing the >> differences. >> >> >> >> >> On Wednesday, September 20, 2023 at 10:19:07 AM UTC+2 Joan Balagueró >> wrote: >> >>> Hello, >>> >>> I have a protobuf message like this into a byte array: >>> >>> 1: { // META element >>> 1: 2 >>> 2: 1 >>> 3: 1 >>> 4: { // CutOffTime element within META >>> 1: 10 >>> 2: 3 >>> } >>> 5: 1 >>> 6: 40 >>> } >>> 2: 9836 // HOTEL element >>> 3: 724 // MARKET element >>> >>> >>> We need to traverse this message and write it to a 'CodeOutputStream', >>> but changing the values of the 'cutoff' element to, for example to '4: { 1: >>> 7, 2: 4 }'. I'm not able to do it, I need some help. >>> >>> A basic algorithm that writes the same protobuf to another byte array >>> but without changing anything works. Here I try the special case of 'META' >>> (key = 1) that contains the 'cutoff' element. >>> >>> Map<Integer, UnknownFieldSet.Field> rootFields = >>> UnknownFieldSet.parseFrom(document).asMap(); >>> >>> for (Map.Entry<Integer, UnknownFieldSet.Field> entry : >>> rootFields.entrySet()) { >>> if (entry.getKey() == 1) { >>> ByteString bs = >>> entry.getValue().getLengthDelimitedList().get(0); >>> output.writeByteArray(1, bs.toByteArray()); >>> } >>> else { >>> entry.getValue().writeTo(entry.getKey(), output); >>> } >>> } >>> >>> >>> Now I try to go a bit further, trying to read the cuotff element, change >>> the values and rewrite them to the 'output'. And here is when I'm not able >>> to solve the problem. Below my try that does not work, it generates a byte >>> array >>> of 69 bytes instead of 73 (I'm losing 4 bytes): >>> >>> Map<Integer, UnknownFieldSet.Field> rootFields = >>> UnknownFieldSet.parseFrom(document).asMap(); >>> >>> for (Map.Entry<Integer, UnknownFieldSet.Field> entry : >>> rootFields.entrySet()) { >>> if (entry.getKey() == 1) { >>> ByteString bs = >>> entry.getValue().getLengthDelimitedList().get(0); >>> Map<Integer, UnknownFieldSet.Field> ufs = >>> UnknownFieldSet.parseFrom(bs).asMap(); >>> >>> for (Map.Entry<Integer, UnknownFieldSet.Field> item >>> : ufs.entrySet()) { >>> if (item.getKey() == 4) { >>> Map<Integer, UnknownFieldSet.Field> cutoff = >>> UnknownFieldSet.parseFrom(item.getValue().getLengthDelimitedList().get(0)).asMap(); >>> cutoff.put(1, >>> UnknownFieldSet.Field.newBuilder().addVarint(7).build()).writeTo(1, output); >>> cutoff.put(2, >>> UnknownFieldSet.Field.newBuilder().addVarint(4).build()).writeTo(1, output); >>> } >>> else { >>> item.getValue().writeTo(item.getKey(), >>> output); >>> } >>> } >>> } >>> else { >>> entry.getValue().writeTo(entry.getKey(), output); >>> } >>> } >>> >>> Any help would be really appreciated. >>> >>> Thanks, >>> >>> Joan. >>> >> -- You received this message because you are subscribed to the Google Groups "Protocol Buffers" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To view this discussion on the web visit https://groups.google.com/d/msgid/protobuf/02a18aa1-705a-4b7f-a199-cfc81c22c7f8n%40googlegroups.com.
