ASP.NET Core中POST接口无法接收Protobuf消息的重复字段
解决ASP.NET Core无法接收Protobuf重复字段的问题
核心原因
Google.Protobuf生成的RepeatedField<string>是只读的get-only集合,ASP.NET Core默认的JSON序列化器(System.Text.Json)无法直接将JSON数组绑定到这个类型——因为序列化器无法向只读集合中添加元素。
解决方法
方法1:启用Protobuf的JSON序列化支持
这是最直接的官方适配方案:
- 安装NuGet包:
Google.Protobuf.AspNetCore - 在ASP.NET Core的启动配置(Program.cs)中,配置JSON序列化选项:
builder.Services.AddControllers() .AddJsonOptions(options => { options.JsonSerializerOptions.Converters.Add(new Google.Protobuf.JsonConverter()); });
配置完成后,System.Text.Json就能正确识别并绑定RepeatedField<T>类型的字段。
方法2:使用DTO中转
如果不想引入额外依赖,可以通过普通DTO接收请求后再转换:
- 定义DTO类:
public class TestArrayDto { public List<string> Strs { get; set; } }
- 在接口中接收DTO并映射到Protobuf生成的类型:
[HttpPost] public IActionResult Post([FromBody] TestArrayDto dto) { var testArray = new TestArray(); testArray.Strs.AddRange(dto.Strs); // 后续业务逻辑处理 return Ok(); }
方法3:自定义模型绑定器
如果需要更灵活的处理逻辑,可以自定义绑定器解析JSON数组到RepeatedField<T>:
public class RepeatedFieldModelBinder : IModelBinder { public Task BindModelAsync(ModelBindingContext bindingContext) { if (bindingContext.ModelType.IsGenericType && bindingContext.ModelType.GetGenericTypeDefinition() == typeof(RepeatedField<>)) { var jsonBuffer = bindingContext.HttpContext.Request.BodyReader.ReadAsync().Result.Buffer; var jsonStr = Encoding.UTF8.GetString(jsonBuffer.FirstSpan); var root = JsonDocument.Parse(jsonStr).RootElement; var targetProp = root.GetProperty(bindingContext.FieldName); var elementType = bindingContext.ModelType.GetGenericArguments()[0]; var list = JsonSerializer.Deserialize(targetProp.GetRawText(), typeof(List<>).MakeGenericType(elementType)); var repeatedField = Activator.CreateInstance(bindingContext.ModelType); var addRangeMethod = bindingContext.ModelType.GetMethod("AddRange"); addRangeMethod?.Invoke(repeatedField, new[] { list }); bindingContext.Result = ModelBindingResult.Success(repeatedField); } return Task.CompletedTask; } }
然后在接口参数上标记绑定器:
[HttpPost] public IActionResult Post([ModelBinder(typeof(RepeatedFieldModelBinder))] TestArray request) { // 业务逻辑处理 return Ok(); }
额外注意事项
- 确保请求的
Content-Type头设置为application/json,因为你发送的是JSON格式负载,而非二进制Protobuf数据。 - 检查
Google.ProtobufNuGet包版本,尽量使用最新稳定版,避免旧版本的兼容性问题。
内容的提问来源于stack exchange,提问作者Magma Jia
相关产品推荐
相关产品推荐

