XiHan.Framework.Protocols.Grpc
gRPC 协议适配器,提供 protocols.grpc@1:把 Expose.Grpc 的操作契约发布成 gRPC 一元方法(服务 {Resource}、方法 {Verb}),以操作的 JSON Schema 作为 protobuf 描述在两种线格式之间转换,并发布由同一份描述生成的 .proto。适用于服务之间要用 gRPC 调用操作的场景。
| 项 | 内容 |
|---|---|
| 包 ID | XiHan.Framework.Protocols.Grpc |
| 环层 | Ring 5(协议与插件) |
| 能力 | 提供 protocols.grpc@1;依赖 kernel.hosting@1 |
| 特性入口 | GrpcProtocolFeature |
| 配置节 | XiHan:Protocols:Grpc |
| 依赖 | XiHan.Framework.Kernel、XiHan.Framework.Hosting.AspNetCore、XiHan.Framework.Localization.Abstractions;Grpc.AspNetCore.Server;共享框架 Microsoft.AspNetCore.App |
| AOT | 兼容(IsAotCompatible) |
| 稳定性 | Preview |
概述
GrpcProtocolFeature 调用 AddGrpc(),登记选项与一个 IServiceMethodProvider:方法在运行时按操作表动态绑定,消息以字节数组传递,不需要编译 .proto,也不依赖 Google.Protobuf。操作表在第一次解析时建成,这时全部特性已装配、登记表已定型。
每个方法调用都是一次独立调用:处理器以请求的 HTTP/2 头建调用上下文(traceparent、baggage、authorization、accept-language、xihan-deadline 或 grpc-timeout),把请求按 Schema 从 protobuf 解码为 JSON 载荷,经完整内核管道执行,再把响应编码回 protobuf。gRPC 方法带 PipelineBypassMetadata,不经 UseXiHan() 的外层调用。失败映射为 gRPC 状态,错误码与 trace-id 放在尾部元数据。
何时使用
调用方是 gRPC 客户端(其他语言的服务、需要 HTTP/2 与二进制线格式的场景)时用它。浏览器与通用 HTTP 客户端用 Protocols.Http。只支持一元方法,流式方法与 gRPC 反射服务未提供。
安装与启用
dotnet add package XiHan.Framework.Protocols.Grpc --prerelease当前是预览版,安装要带 --prerelease;从源码或本地包源引用见快速上手。Profiles.Full 已包含本包。
using XiHan.Framework.Hosting.AspNetCore;
using XiHan.Framework.Profiles.Standard;
using XiHan.Framework.Protocols.Grpc;
using XiHan.Framework.Protocols.Grpc.Services;
var builder = WebApplication.CreateBuilder(args);
builder.AddXiHan(xihan => xihan.UseStandardProfile().UseFeature<GrpcProtocolFeature>());
var app = builder.Build();
app.UseXiHan();
app.MapXiHanGrpc(); // /{package}.{Service}/{Method}
app.MapXiHanProto(); // GET /operations.proto
app.Run();不用 TLS 时给 gRPC 单开一个 HTTP/2 端点(h2c):
{
"Kestrel": {
"Endpoints": {
"Http": { "Url": "http://localhost:5000" },
"Grpc": { "Url": "http://localhost:5001", "Protocols": "Http2" }
}
}
}配置
| 键 | 类型 | 缺省 | 说明 |
|---|---|---|---|
XiHan:Protocols:Grpc:Package | string | 空 | protobuf 包名(小写标识符以点分隔),写进 .proto 的 package,也是方法路径前缀 |
XiHan:Protocols:Grpc:Methods:<操作 ID> | string | — | Service/Method,覆盖推导的名字 |
{
"XiHan": {
"Protocols": {
"Grpc": {
"Package": "acme.orders",
"Methods": { "orders.list": "Orders/ListAll" }
}
}
}
}主要类型
| 类型 | 说明 |
|---|---|
GrpcProtocolFeature | 特性入口 |
GrpcProtocolOptions | Package、Methods;MethodFor(contract);FromConfiguration |
Services.OperationGrpcEndpointRouteBuilderExtensions | MapXiHanGrpc()、MapXiHanProto(pattern)(缺省 /operations.proto,text/plain) |
Methods.GrpcMethodConvention | Derive(contract):资源段与动词的 PascalCase |
Methods.GrpcMethodName | 服务名与方法名;PathFor(package)、FullServiceName(package)、Parse("Orders/List") |
Methods.GrpcOperationTable | 暴露给 gRPC 的操作、各自的请求与响应消息、生成的 .proto 文本 |
Proto.ProtoSchema | FromJsonSchema(schema):由 JSON Schema 建 protobuf 消息描述 |
Proto.ProtoDecoder、Proto.ProtoEncoder | protobuf 与 JSON 之间的转换 |
Proto.ProtoFileBuilder | 由消息描述生成 .proto |
Proto.ProtoMessage、ProtoField、ProtoValueType、ProtoKind、ProtoCardinality | 消息描述模型 |
GrpcErrors | 本包的错误码 |
使用示例
客户端用发布出的 .proto 调用(samples/SimpleApp):
curl -s localhost:5000/operations.proto -o operations.proto
grpcurl -plaintext -proto operations.proto -H "authorization: ApiKey dev-alice-key" \
-d '{"name":"widget","amount":3}' localhost:5001 Orders/CreateJSON Schema 到 protobuf 的映射表与生成的 .proto 见 gRPC、MCP 与 CloudEvents。
行为与限制
- 暴露给 gRPC 的操作必须有 Schema;名字、Schema 与消息形状的问题都在映射时失败,应用启动不起来。
- 方法名:服务 = 资源段的 PascalCase(
order-lines→OrderLines),方法 = 动词的 PascalCase;XiHan:Protocols:Grpc:Methods:<操作 ID>=Service/Method显式覆盖;包名XiHan:Protocols:Grpc:Package写进.proto的package,也是路径前缀(/{package}.Orders/Create)。名字不合法或重复即启动失败。发布范围是Expose含Grpc且非Stability.Internal的操作。 - 消息映射(
ProtoSchema):消息名取 Schema 的title(封闭泛型带实参名,如PageResultOfUserResponse,ADR-0034),$defs里的每个对象定义一个消息;字段号按 Schema 属性顺序从 1 起;string→ string(base64 → bytes)、boolean→ bool、integer按formatint32 / int64(无格式 → 十进制文本)、number按formatfloat / double(decimal、无格式 → 十进制文本)、数组 → repeated、additionalProperties→ map<string, T>、$ref→ 嵌套消息(指向字符串枚举这类标量定义时按该标量映射为 string,不建消息也不建 proto enum)、可空 → optional、无约束 → JSON 文本。嵌套数组与映射里的映射不可表示,启动失败。.proto文件由同一份描述生成并经MapXiHanProto()(GET /operations.proto)发布给客户端。 - 调用来源记
grpc与方法全名,远端地址与 User-Agent 沿用 HTTP/2 请求(ADR-0043);端点绕过UseXiHan()的回写,响应完全由 gRPC 处理器产出。流式方法与 gRPC 反射服务未提供。 - 线上缺席的布尔、数值、
repeated、map字段按 proto3 默认值补进 JSON;字符串、字节、嵌套消息缺席即缺席。 - 字符串枚举映射为
string,不建 protoenum;integer无格式与decimal映射为十进制文本。 - 应用未就绪(启动中或正在停止)时以
Unavailable拒绝、不进管道:尾部元数据带xihan-error-code: KERNEL_UNAVAILABLE_001与xihan-trace-id,grpc-message按accept-language翻译。
| KIND | gRPC 状态 |
|---|---|
VALIDATION | InvalidArgument |
NOTFOUND | NotFound |
CONFLICT | Aborted |
DENIED | PermissionDenied;SECURITY_DENIED_001、SECURITY_DENIED_003 为 Unauthenticated |
UNAVAILABLE | Unavailable |
TIMEOUT | DeadlineExceeded |
CANCELLED | Cancelled |
| 其他 | Internal |
| 错误码 | 情形 |
|---|---|
PROTOCOLS_VALIDATION_005 | 请求不是合法的 protobuf 或与 Schema 不符(InvalidArgument) |
PROTOCOLS_VALIDATION_006 | 暴露给 gRPC 的操作没有 Schema,或 Schema 无法映射为 protobuf(启动失败) |
PROTOCOLS_VALIDATION_007 | 推导或配置的服务 / 方法名不合法(启动失败) |
PROTOCOLS_CONFLICT_004 | 两个操作得到同一个服务 / 方法名(启动失败) |
PROTOCOLS_CONFLICT_003 | 同名 protobuf 消息在不同操作里形状不同(启动失败) |
PROTOCOLS_UNEXPECTED_001 | 响应无法按 Schema 编码为 protobuf(Internal) |
尾部元数据 xihan-error-code 是错误码,xihan-trace-id 是 trace-id(成功时也有);grpc-message 按 accept-language 翻译。
相关
- gRPC、MCP 与 CloudEvents、操作契约
- Hosting.AspNetCore、Protocols.Http、Kernel.Generators
- 规范:
spec/protocol/grpc.md《gRPC 载体》、RFC-0011《操作契约与 XGI》
