本文档为开发者提供标准化的 gRPC 接口开发指南,涵盖从协议定义、服务实现到测试验证的全流程规范。适用于 .NET 技术栈的微服务场景,确保跨服务通信的高效性、兼容性和可维护性。
1. 系统内置类型说明 1.1 基础类型示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 [ProtoContract(ImplicitFields = ImplicitFields.AllPublic) ] public class ProtoLong { public long Value { get ; set ; } public ProtoLong () { } public ProtoLong (long value ) => Value = value ; public static implicit operator ProtoLong (long value ) => new (value ); public static implicit operator long (ProtoLong result ) => result.Value; } [ProtoContract(ImplicitFields = ImplicitFields.None) ] public class GrpcOutput <T >{ [ProtoMember(1) ] public bool Success { get ; set ; } [ProtoMember(2) ] public string Code { get ; set ; } [ProtoMember(3) ] public string Msg { get ; set ; } [ProtoMember(4) ] public T Data { get ; set ; } }
1.2 系统基础类型对照表
类型名称
原始类型
使用场景
序列化说明
ProtoBoolean
bool
布尔值传输
直接映射true/false
ProtoDateTime
DateTime
日期时间传输(UTC格式)
使用 ISO8601 字符串格式
ProtoDecimal
decimal
高精度数值传输
转换为字符串避免精度丢失
ProtoInt
int
整型数值传输
直接映射 32 位整数
ProtoList<T>
List<T>
集合类型传输
支持泛型集合序列化
ProtoString
string
字符串传输
UTF-8 编码
ProtoLong
long
长整型传输
解决 int64 边界问题
GrpcOutput<T>
T
标准化响应格式
包含业务状态和数据的包装器
2. 请求/响应模型 2.1 输入模型示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 using ProtoBuf;namespace MyCompanyName.Modules.Member.Api.Contracts.Services.Module.Input ;[ProtoContract(ImplicitFields = ImplicitFields.None) ] public class ModuleAddGrpcInput { [ProtoMember(1) ] public string Name { get ; set ; } [ProtoMember(2) ] public ProtoDateTime CreateTime { get ; set ; } }
2.2 ImplicitFields 枚举说明
枚举成员
描述
推荐场景
None
不进行隐式标记分配,所有成员需显式使用[ProtoMember] 属性指定标记
推荐 ,提供最高稳定性和可控性,即使成员名称变化也不会影响序列化
AllPublic
所有公共成员(属性和字段)按字母顺序隐式分配标记,从ImplicitFirstTag 开始
当需要将公共 API 作为契约、且成员名称稳定不变时使用
AllFields
所有字段(包括公共和非公共字段)按字母顺序隐式分配标记
用于序列化内部状态,通常用于实现序列化而非公共 API
使用建议 :若需稳定的序列化和反序列化,推荐使用 [ProtoMember] 显式分配标记。若希望快速实现且成员名称不会频繁变化,可使用 ImplicitFields.AllPublic。
2.3 模型定义规范
所有 DTO 必须使用 [ProtoContract] 和 [ProtoMember] 标记
ProtoMember 编号必须连续且唯一,从 1 开始递增
禁止 修改已发布字段的编号,新增成员使用后续数字
枚举类型必须指定 [ProtoContract] 和 [ProtoMember(1)]
3. 服务接口定义 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 using MyCompanyName.Modules.Member.Api.Contracts.Services.Module.Input;using MyCompanyName.Modules.Member.Api.Core.Consts;using ProtoBuf.Grpc;using System.ServiceModel;using System.Threading.Tasks;using ZhonTai.Admin.Core.Protos;namespace MyCompanyName.Modules.Member.Api.Contracts.GrpcServices.Module ;[ServiceContract(ConfigurationName = ApiConsts.AreaName) ] public interface IModuleGrpcService { [OperationContract ] Task<GrpcOutput<ProtoLong>> AddAsync(ModuleAddGrpcInput input, CallContext context = default ); }
属性说明
属性
说明
ConfigurationName
用于自动化客户端生成和服务发现,值需与ApiConsts.AreaName 常量保持一致
OperationContract
可选,隐式继承自基类,标识可远程调用的服务方法
4. 服务实现示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 using ProtoBuf.Grpc;using System.Threading.Tasks;using ZhonTai.Admin.Core.Protos;using Mapster;using MyCompanyName.Modules.Member.Api.Contracts.Services.Module;using MyCompanyName.Modules.Member.Api.Contracts.Services.Module.Input;using MyCompanyName.Modules.Member.Api.Contracts.GrpcServices.Module;namespace MyCompanyName.Modules.Member.Api.GrpcServices.Module ;public class ModuleGrpcService : IModuleGrpcService { private readonly IModuleService _moduleService; public ModuleGrpcService (IModuleService moduleService ) { _moduleService = moduleService; } public async Task<GrpcOutput<ProtoLong>> AddAsync(ModuleAddGrpcInput input, CallContext context) { try { var id = await _moduleService.AddAsync(input.Adapt<ModuleAddInput>()); return new GrpcOutput<ProtoLong> { Success = true , Data = id }; } catch (Exception ex) { return new GrpcOutput<ProtoLong> { Code = "" , Msg = ex.Message }; } } }
5. 跨模块调用 gRPC 服务 5.1 添加项目引用 在 MyCompanyName.Modules.Biz.Api 接口库的 .csproj 文件中添加对目标模块契约项目的引用:
1 2 3 <ItemGroup > <ProjectReference Include ="..\..\MyCompanyName.Modules.Member\MyCompanyName.Modules.Member.Api.Contracts\MyCompanyName.Modules.Member.Api.Contracts.csproj" /> </ItemGroup >
5.2 配置 appsettings.json 在 MyCompanyName.Modules.Biz.Host 项目的 appsettings.json 中添加 gRPC 配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 "RpcConfig" : { "Http" : { "Enable" : true , "AssemblyNames" : [ "ZhonTai.Admin.Contracts" ] } , "Grpc" : { "Enable" : true , "AssemblyNames" : [ "ZhonTai.Admin.Core" , "MyCompanyName.Modules.Member.Api.Contracts" ] , "ServerAssemblyNames" : [ ] } , "Endpoints" : [ { "Name" : "admin" , "HttpUrl" : "http://localhost:18010" , "GrpcUrl" : "http://localhost:18011" } , { "Name" : "mem" , "HttpUrl" : "http://localhost:18020" , "GrpcUrl" : "http://localhost:18021" } ] }
配置项说明
配置项
说明
Grpc.AssemblyNames
添加要扫描的 gRPC 客户端程序集(gRPC 服务接口所在的程序集)
Grpc.ServerAssemblyNames
添加要扫描的 gRPC 服务端程序集(gRPC 服务实现所在的程序集)
Endpoints
声明目标服务的通信地址
Name
服务标识符,需与契约项目中的服务名称对应
GrpcUrl
目标服务的 Grpc 端点地址
5.3 服务调用示例 在业务服务中通过构造函数注入 gRPC 服务客户端:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 using FreeScheduler;using Microsoft.AspNetCore.Authorization;using Microsoft.AspNetCore.Mvc;using MyCompanyName.Modules.Biz.Api.Contracts.Domain.Module;using MyCompanyName.Modules.Biz.Api.Contracts.Services.Module;using MyCompanyName.Modules.Biz.Api.Contracts.Services.Module.Input;using MyCompanyName.Modules.Biz.Api.Contracts.Services.Module.Output;using MyCompanyName.Modules.Biz.Api.Core.Consts;using MyCompanyName.Modules.Biz.Api.Core.Repositories;using MyCompanyName.Modules.Member.Api.Contracts.GrpcServices.Module.Input;using Newtonsoft.Json;using System.Threading.Tasks;using ZhonTai;using ZhonTai.Admin.Core.Dto;using ZhonTai.Admin.Services;using ZhonTai.DynamicApi;using ZhonTai.DynamicApi.Attributes;namespace MyCompanyName.Modules.Biz.Api.Services.Module ;[Order(1010) ] [DynamicApi(Area = ApiConsts.AreaName) ] public class ModuleService : BaseService , IModuleService , IDynamicApi { private readonly AppRepositoryBase<ModuleEntity> _moduleRep; private readonly IModuleGrpcService _moduleGrpcService; public ModuleService ( AppRepositoryBase<ModuleEntity> moduleRep, IModuleGrpcService moduleGrpcService ) { _moduleRep = moduleRep; _moduleGrpcService = moduleGrpcService; } public async Task<ModuleGetOutput> GetAsync (long id ) { var grpcResult = await _moduleGrpcService.AddAsync(new ModuleAddGrpcInput { Name = "Grpc测试" }); var result = await _moduleRep.GetAsync<ModuleGetOutput>(id); return result; } }
建议 :实际开发中结合框架提供的中间件进行统一的服务治理(如熔断、限流等)。
6. 测试验证流程 6.1 服务启动验证 运行项目后,在命令台中看到以下内容则表示 Grpc 服务方法注册成功:
1 2 Added gRPC method 'Add' to service 'MyCompanyName.Modules.Member.Api.Contracts.GrpcServices.Module.ModuleGrpcService'. Method type: Unary, HTTP method: , route pattern: '/MyCompanyName.Modules.Member.Api.Contracts.GrpcServices.Module.ModuleGrpcService/Add'.
6.2 Postman 测试步骤
点击 New 按钮,弹出对话框选择 gRPC
在 Enter URL 文本框中输入 grpc://localhost:18021(URL 格式:grpc://{host}:{port})
右侧下拉框中选择 Use Server Reflection ,出现 Add 方法则表示反射成功
选择 ModuleGrpcService/Add 方法
构造请求报文:
1 2 3 4 5 6 { "Name" : "TestModule" , "CreateTime" : { "Value" : "2024-03-20T08:00:00Z" } }
点击 Invoke 按钮,验证响应结构:
1 2 3 4 5 6 { "Success" : true , "Data" : { "Value" : 649219021422661 } }
7. 版本兼容策略 7.1 变更类型处理
变更类型
允许性
处理方案
新增字段
✅允许
客户端需处理字段缺失情况
删除字段
⚠️禁止
标记Obsolete,保留至少两个版本周期
修改字段类型
⛔禁止
必须创建新版本接口
重命名字段
⛔禁止
使用[ProtoMember] 别名功能实现平滑过渡
7.2 版本标识规则 在服务契约中声明版本号:
1 2 3 4 5 [ServiceContract(Name = "MemberService_v1" ) ] public interface IModuleGrpcService { }
#中台/分布式微服务 #分布式 #分布式/消息传递 #API接口 #中台/配置文件