C# gRPC服务创建方法 C#如何创建和调用gRPC服务

3次阅读

用 dotnet new grpc 创建项目是最直接起点,生成含 greeterservice 的完整 grpc 服务,需注意 https/http/2 配置、.proto 文件位置与生成操作、服务注册 app.mapgrpcservice()、客户端必须通过 grpcchannel 调用、正确处理 statuscode=unavailable(连接问题)与 internal(服务端异常)。

C# gRPC服务创建方法 C#如何创建和调用gRPC服务

dotnet new grpc 创建基础服务项目

这是最直接的起点,命令会生成包含 GreeterService 示例的完整可运行 gRPC 服务(基于 ASP.NET Core)。

执行后你会得到一个带 Program.csProtos/greet.protoServices/GreeterService.cs 的项目。关键点在于:它默认启用 https 和 HTTP/2,且 app.MapGrpcService<greeterservice>()</greeterservice> 是注册服务的必需调用。

  • 若在非开发环境部署,需确保服务器支持 HTTP/2(如 Kestrel 默认支持,iiswindows Server 2016+ + TLS 1.2+)
  • .proto 文件必须放在 Protos/ 目录并设为 Protobuf 生成操作,否则 dotnet build 不会生成 C# 绑定类
  • 不要手动修改生成的 *.Grpc.cs 文件——它们每次构建都会被覆盖

定义接口时注意 servicerpc 的写法

gRPC 的契约由 .proto 文件驱动,C# 类型和行为完全由此决定。错误的 proto 定义会导致客户端和服务端无法通信,甚至编译不报错但运行时报 StatusCode=Unimplemented

常见问题包括:

  • 遗漏 option csharp_namespace = "MyApp.Protos"; —— 导致生成的 C# 类不在预期命名空间,引用失败
  • rpc SayHello(HelloRequest) returns (HelloReply); 中的 HelloRequestHelloReply 必须已用 message 正确定义,且字段名首字母小写(如 String name = 1; → C# 属性为 Name
  • 流式方法要显式标注:比如 rpc StreamingCall(stream ClientMessage) returns (stream ServerMessage);,否则生成器不会产生 IAsyncStreamReaderIServerStreamWriter

客户端调用必须用 Channel + 生成的 *Client

不能像调用普通类一样 new 一个服务类;必须通过 GrpcChannel.ForAddress("https://localhost:5001") 创建通道,再传给生成的客户端构造函数

典型调用模式:

using var channel = GrpcChannel.ForAddress("https://localhost:5001"); var client = new Greeter.GreeterClient(channel); var reply = await client.SayHelloAsync(new HelloRequest { Name = "Alice" });
  • HTTP/2 要求地址协议明确:用 https://(开发时可配 http://,但需在 channel 构造时加 new GrpcChannelOptions { HttpHandler = new SocketsHttpHandler { EnableMultipleHttp2Connections = true } }
  • 若服务启用了 TLS 但客户端证书验证失败,会抛 System.Net.Http.HttpRequestException,提示 “The ssl connection could not be established” —— 此时需配置 GrpcChannelOptions.Credentials 或临时禁用验证(仅限开发)
  • 短生命周期调用建议复用 GrpcChannel 实例(它是线程安全的),不要为每次请求新建 channel

调试时先确认 StatusCode=Internal 还是 StatusCode=Unavailable

这两个错误看起来像网络问题,但根源完全不同:

  • StatusCode=Unavailable:通常是连接失败(地址错、端口未监听、防火墙拦截、TLS 协商失败),检查 dotnet run 是否真在监听,用 curl -v https://localhost:5001 看是否返回 HTTP/2 404(说明服务起来了)
  • StatusCode=Internal:大概率是服务端代码异常未捕获,比如 SayHello 方法里 throw 了未处理的 Exception —— gRPC 会将其转为 Internal 并丢掉原始;应在服务端添加全局异常过滤器或日志中间件捕获
  • 客户端收到异常时,exception.Status.Detail 可能含服务端返回的错误信息(前提是服务端用了 Status(StatusCode.Internal, "xxx") 显式设置)

proto 文件改了之后,务必重新生成客户端和服务端代码;visual studio 不总会自动触发,可手动运行 dotnet build 或右键 .proto 文件选 “重新生成”。

text=ZqhQzanResources