You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自定义Protobuf Decimal类型在gRPC+REST下的返回异常问询

自定义Protobuf Decimal类型在gRPC REST接口返回异常的解决方案

你遇到的问题并非正常行为,核心原因是.NET的gRPC HTTP API默认依赖的System.Text.Json序列化机制,无法自动识别自定义的Protobuf DecimalValue类型,导致返回JSON时字段被错误重置为0。你的需求完全可以实现,只需为自定义类型配置JSON转换器并正确注册,同时验证映射逻辑。

解决方案步骤

1. 为DecimalValue实现JSON转换器

创建一个自定义JsonConverter,处理DecimalValue与JSON的双向序列化:

using System.Text.Json;
using System.Text.Json.Serialization;
using CustomType.V1; // 替换为你的DecimalValue所在命名空间

public class DecimalValueJsonConverter : JsonConverter<DecimalValue>
{
    public override DecimalValue Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        if (reader.TokenType != JsonTokenType.StartObject)
            throw new JsonException("Expected object for DecimalValue");

        long units = 0;
        int nanos = 0;

        while (reader.Read())
        {
            if (reader.TokenType == JsonTokenType.EndObject) break;
            if (reader.TokenType != JsonTokenType.PropertyName)
                throw new JsonException("Expected property name");

            var propName = reader.GetString();
            reader.Read();

            switch (propName)
            {
                case "units":
                    units = reader.GetInt64();
                    break;
                case "nanos":
                    nanos = reader.GetInt32();
                    break;
                default:
                    reader.Skip();
                    break;
            }
        }

        return new DecimalValue { Units = units, Nanos = nanos };
    }

    public override void Write(Utf8JsonWriter writer, DecimalValue value, JsonSerializerOptions options)
    {
        writer.WriteStartObject();
        writer.WriteNumber("units", value.Units);
        writer.WriteNumber("nanos", value.Nanos);
        writer.WriteEndObject();
    }
}

2. 注册转换器到gRPC HTTP API配置

在Program.cs中找到gRPC相关配置,添加转换器到JSON转码选项:

builder.Services.AddGrpc()
    .AddJsonTranscoding(options =>
    {
        options.JsonSerializerOptions.Converters.Add(new DecimalValueJsonConverter());
    });

如果同时使用普通ASP.NET Core API,也要在控制器的JSON配置中注册:

builder.Services.AddControllers()
    .AddJsonOptions(options =>
    {
        options.JsonSerializerOptions.Converters.Add(new DecimalValueJsonConverter());
    });

3. 验证AutoMapper映射逻辑

你使用Adapt<FindFooResponse>进行模型转换,需确保领域模型到FooRpc的映射正确处理了货币值到DecimalValue的转换。比如领域模型有decimal Price属性,映射配置应类似:

CreateMap<FooDomain, FooRpc>()
    .ForMember(dest => dest.Price, opt => opt.MapFrom(src =>
    {
        var price = src.Price;
        long units = (long)price;
        int nanos = (int)((price - units) * 1_000_000_000);
        return new DecimalValue { Units = units, Nanos = nanos };
    }));

4. 快速排查测试

直接构造DecimalValue实例返回,排除映射问题:

public override async Task<FindFooResponse> FindFoo(Empty request, ServerCallContext context)
{
    return new FindFooResponse
    {
        Foo = { new FooRpc { Price = new DecimalValue { Units = 200, Nanos = 990000000 } } }
    };
}

如果此测试返回正确JSON,说明问题出在映射逻辑而非序列化配置。

内容的提问来源于stack exchange,提问作者José Romero

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 19:20:51