0Pricing
C# Academy · 课时

gRPC 与 Protobuf 基础

在 .proto 文件中定义服务契约,使用 Grpc.Tools 生成 C# 代码,并了解 gRPC 传输机制。

gRPC 与 Protobuf 基础 是 CoddyKit 上的免费 C# Academy 课时。 这是第 1 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 C# Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 C# Academy 课程共包含 4 节课。

什么是 gRPC

gRPC 是由 Google 开发的高性能、与编程语言无关的 RPC 框架。它使用 HTTP/2 进行传输,并使用 Protocol Buffers(Protobuf) 作为序列化格式——与通过 HTTP/1.1 传输 JSON 相比,速度更快且更加紧凑。

Protocol Buffers:IDL

您可以在 .proto 文件中定义服务契约。Protobuf IDL(接口定义语言)具有强类型且与语言无关——同一个文件可以生成 C#、Go、Python 等语言的客户端和服务器端代码。

// greet.proto
syntax = "proto3";

option csharp_namespace = "GrpcService";

package greet;

service Greeter {
  rpc SayHello (HelloRequest) returns (HelloReply);
}

message HelloRequest {
  string name = 1;
}

message HelloReply {
  string message = 1;
}

在 .NET 中设置 gRPC 服务器

使用 dotnet new grpc 创建 gRPC 项目。将 .proto 文件添加到项目中,Grpc.Tools 会在构建时自动生成 C# 类。

// .csproj snippet
<ItemGroup>
  <Protobuf Include="Protos\greet.proto" GrpcServices="Server" />
</ItemGroup>

// Program.cs
builder.Services.AddGrpc();

var app = builder.Build();
app.MapGrpcService<GreeterService>();
app.Run();

实现 gRPC 服务

继承生成的基类并重写 RPC 方法。框架会自动处理序列化、HTTP/2 帧处理和路由。

using Grpc.Core;
using GrpcService;

public class GreeterService : Greeter.GreeterBase
{
    private readonly ILogger<GreeterService> _logger;
    public GreeterService(ILogger<GreeterService> logger) => _logger = logger;

    public override Task<HelloReply> SayHello(
        HelloRequest request,
        ServerCallContext context)
    {
        _logger.LogInformation("Saying hello to {Name}", request.Name);
        return Task.FromResult(new HelloReply
        {
            Message = $"Hello, {request.Name}!"
        });
    }
}

创建 gRPC 客户端

Protobuf 编译器还会生成强类型的客户端类。使用 GrpcChannel 连接并调用服务,就像调用本地方法一样。

// Client project: add Grpc.Net.Client package
using var channel = GrpcChannel.ForAddress("https://localhost:7042");
var client = new Greeter.GreeterClient(channel);

var reply = await client.SayHelloAsync(
    new HelloRequest { Name = "Alice" });

Console.WriteLine(reply.Message); // Hello, Alice!

Protobuf 类型与字段编号

Protobuf 消息中的每个字段都有唯一的字段编号(1–536870911)。字段编号会编码到二进制格式中——部署后绝不能更改,否则会破坏向后兼容性。

message Product {
  int32  id          = 1;
  string name        = 2;
  double price       = 3;
  int32  stock       = 4;
  bool   is_active   = 5;
  repeated string tags = 6; // array
}

// Supported scalar types:
// int32, int64, uint32, uint64, float, double
// bool, string, bytes, enum

枚举与嵌套消息

Protobuf 支持枚举和嵌套消息类型。您可以使用它们在服务契约中建模复杂的领域对象。

enum OrderStatus {
  ORDER_STATUS_UNSPECIFIED = 0;
  ORDER_STATUS_PENDING     = 1;
  ORDER_STATUS_SHIPPED     = 2;
  ORDER_STATUS_CANCELLED   = 3;
}

message Order {
  int32       id       = 1;
  OrderStatus status   = 2;
  repeated OrderLine lines = 3;
}

message OrderLine {
  int32  product_id = 1;
  int32  quantity   = 2;
  double price      = 3;
}

HTTP/2 与 gRPC 传输

gRPC 使用支持多路复用的 HTTP/2——在单个 TCP 连接上并发执行多个 RPC 调用——与 HTTP/1.1 相比,可以降低延迟和连接开销。

// gRPC requires HTTP/2
// For local dev with HTTP (not HTTPS), enable HTTP/2 cleartext:
builder.WebHost.ConfigureKestrel(opt =>
    opt.ListenLocalhost(5000, o => o.Protocols = HttpProtocols.Http2));

// Client for cleartext (dev only)
AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);
using var channel = GrpcChannel.ForAddress("http://localhost:5000");

使用 StatusCode 处理错误

gRPC 使用自己的状态码(不同于 HTTP)。抛出带有 Status 的 RpcException,即可向客户端发送类型化的错误响应。

public override Task<ProductReply> GetProduct(
    ProductRequest request,
    ServerCallContext context)
{
    var product = _repo.FindById(request.Id);
    if (product is null)
        throw new RpcException(
            new Status(StatusCode.NotFound, $"Product {request.Id} not found"));

    return Task.FromResult(MapToReply(product));
}

用于开发的 gRPC 反射

启用 gRPC 反射后,grpcurl 和 Postman 等工具无需直接访问 .proto 文件即可发现您的服务。

// dotnet add package Grpc.AspNetCore.Server.Reflection

builder.Services.AddGrpcReflection();

if (app.Environment.IsDevelopment())
    app.MapGrpcReflectionService();

// Now use grpcurl:
// grpcurl -plaintext localhost:5000 list
// grpcurl -plaintext localhost:5000 greet.Greeter/SayHello

真实案例:微服务产品查询

一个产品服务公开了供订单服务内部使用的 gRPC 端点,这是经典的服务间通信模式。

// product.proto
service ProductService {
  rpc GetProduct (GetProductRequest) returns (ProductResponse);
  rpc ListProducts (ListProductsRequest) returns (ListProductsResponse);
}

// Order service calls it:
public class OrderService
{
    private readonly ProductService.ProductServiceClient _products;
    public OrderService(ProductService.ProductServiceClient p) => _products = p;

    public async Task<Order> PlaceOrderAsync(int productId, int qty)
    {
        var product = await _products.GetProductAsync(
            new GetProductRequest { Id = productId });
        return new Order { ProductName = product.Name, Quantity = qty };
    }
}

快速检查

为什么部署后绝不能更改现有的 Protobuf 字段编号?

回顾:gRPC 与 Protobuf 基础

要点:

  • gRPC 使用 HTTP/2 + Protobuf,实现快速且强类型的服务间通信
  • 在 .proto 文件中定义服务契约,并在构建时生成代码
  • 字段编号用于线路编码,绝不能更改或重复使用
  • 继承生成的基类并重写 RPC 方法
  • 使用带有 StatusCode 的 RpcException 返回类型化的错误响应
  • 在开发环境中启用 gRPC 反射,为工具提供支持

常见问题解答

「gRPC 与 Protobuf 基础」课时是免费的吗?

是的 — 「gRPC 与 Protobuf 基础」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 C# Academy 课程的其余内容,请升级到 CoddyKit PRO。 C# Academy 课程共包含 4 节课。

「gRPC 与 Protobuf 基础」这节课中我会学到什么?

在 .proto 文件中定义服务契约,使用 Grpc.Tools 生成 C# 代码,并了解 gRPC 传输机制。 你通过在浏览器中直接运行的动手代码来练习 C# Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 C# Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 C# Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 1 节课,共 4 节。

「gRPC 与 Protobuf 基础」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 C# Academy 课中编写并运行代码吗?

能。每节 C# Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. gRPC 与 Protobuf 基础
  2. 一元与服务器流式 RPC
  3. 客户端与双向流式传输
  4. 截止时间、取消与拦截器
← 返回 C# Academy