gRPC是基于HTTP/2协议的高性能RPC框架,在C#生态中可以通过官方提供的Grpc.Net包快速集成,广泛用于微服务间的通信场景。下面将从基础使用、最佳实践、常见坑点三个维度展开说明。

C#中使用gRPC的基础步骤
1. 定义proto接口文件
首先需要在项目中创建.proto文件,定义服务接口和消息结构,示例如下:
syntax = "proto3";
option csharp_namespace = "GrpcDemo.Service";
package greet;
// 定义请求消息
message HelloRequest {
string name = 1;
}
// 定义响应消息
message HelloReply {
string message = 1;
}
// 定义服务接口
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply);
}
2. 安装必要依赖包
服务端和客户端项目需要分别安装对应的NuGet包:
- 服务端项目安装
Grpc.AspNetCore - 客户端项目安装
Grpc.Net.Client、Google.Protobuf、Grpc.Tools
3. 实现服务端逻辑
创建继承自生成的服务基类的服务实现类,重写对应的方法:
using Grpc.Core;
using GrpcDemo.Service;
namespace GrpcDemo.Server.Services
{
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("收到请求,参数name为{name}", request.Name);
return Task.FromResult(new HelloReply
{
Message = $"你好,{request.Name}"
});
}
}
}
然后在Program.cs中注册服务并启用gRPC端点:
var builder = WebApplication.CreateBuilder(args);
// 注册gRPC服务
builder.Services.AddGrpc();
var app = builder.Build();
// 映射gRPC服务端点
app.MapGrpcService<GreeterService>();
app.MapGet("/", () => "gRPC服务运行中");
app.Run();
4. 编写客户端调用代码
客户端通过GrpcChannel创建客户端实例发起调用:
using Grpc.Net.Client;
using GrpcDemo.Service;
namespace GrpcDemo.Client
{
class Program
{
static async Task Main(string[] args)
{
// 创建gRPC通道,地址为服务端的监听地址
using var channel = GrpcChannel.ForAddress("https://localhost:5001");
// 创建客户端实例
var client = new Greeter.GreeterClient(channel);
// 发起调用
var reply = await client.SayHelloAsync(new HelloRequest { Name = "C#开发者" });
Console.WriteLine($"收到响应:{reply.Message}");
}
}
}
C# gRPC的最佳实践
1. 合理管理GrpcChannel生命周期
GrpcChannel是重量级对象,内部维护了连接池和HTTP/2连接,推荐全局复用单个实例,不要每次调用都创建新的通道,避免不必要的资源开销。
2. 规范proto文件命名与命名空间
proto文件的包名、csharp_namespace要统一规范,避免不同服务间的命名冲突,消息字段的编号一旦确定不要随意修改,否则会导致序列化兼容问题。
3. 利用拦截器实现通用逻辑
可以通过实现Interceptor类添加日志、认证、限流等通用逻辑,不需要在每个服务方法中重复编写:
using Grpc.Core;
using Grpc.Core.Interceptors;
namespace GrpcDemo.Server.Interceptors
{
public class LoggingInterceptor : Interceptor
{
private readonly ILogger<LoggingInterceptor> _logger;
public LoggingInterceptor(ILogger<LoggingInterceptor> logger)
{
_logger = logger;
}
public override async Task<TResponse> UnaryServerHandler<TRequest, TResponse>(
TRequest request,
ServerCallContext context,
UnaryServerMethod<TRequest, TResponse> continuation)
{
_logger.LogInformation("调用方法:{method},请求参数:{request}", context.Method, request);
var response = await continuation(request, context);
_logger.LogInformation("方法:{method}调用完成", context.Method);
return response;
}
}
}
注册拦截器:
builder.Services.AddGrpc(options =>
{
options.Interceptors.Add<LoggingInterceptor>();
});
4. 配置合适的超时与重试策略
客户端调用时根据业务场景配置合理的超时时间,同时可以结合Polly等库实现重试逻辑,提升调用的稳定性。
C# gRPC常见坑点及解决方案
1. proto文件未正确生成代码
问题表现:引用proto中定义的消息或服务时报找不到类型。解决方案:检查proto文件的属性,确保生成操作设置为Protobuf,且选项正确配置为Server或Client。
2. 服务端返回null导致客户端异常
gRPC不允许返回null值,若服务方法返回的消息字段为值类型,没有赋值的话会序列化为默认值,引用类型未赋值会直接抛出异常。解决方案:确保所有返回的消息字段都显式赋值,或者合理定义默认值。
3. HTTP/2协议不支持问题
问题表现:客户端调用时报不支持HTTP/2的错误。解决方案:确保服务端启用了HTTPS,或者配置Kestrel允许HTTP/2明文传输,客户端调用地址也要对应调整。
4. 大消息体传输异常
gRPC默认的消息大小限制较小,传输大内容时会抛出异常。解决方案:在服务端和客户端的配置中调整最大接收消息大小:
// 服务端配置
builder.Services.AddGrpc(options =>
{
options.MaxReceiveMessageSize = 10 * 1024 * 1024; // 10MB
options.MaxSendMessageSize = 10 * 1024 * 1024;
});
// 客户端配置
var channel = GrpcChannel.ForAddress("https://localhost:5001", new GrpcChannelOptions
{
MaxReceiveMessageSize = 10 * 1024 * 1024
});
5. 异步方法未正确等待
问题表现:调用异步gRPC方法时未使用await,导致程序提前退出或者获取不到返回结果。解决方案:所有返回Task或AsyncUnaryCall的调用都需要正确使用await等待结果,避免遗漏异步操作。
gRPCC#protobufASP.NET_Core修改时间:2026-07-02 19:09:22