syntax = "proto3"; package Greet; // The greeting service definition. service Greeter { // Sends a greeting rpc SayHello (HelloRequest) returns (HelloReply) {} } // The request message containing the user's name. message HelloRequest { string name = 1; } // The response message containing the greetings. message HelloReply { string message = 1; }
定义Greeter服务。
这个Greeter服务定义SayHello请求。
SayHello发送HelloRequest消息并接收HelloResponse信息:
那么你可能要问了,这个.proto文件是如何包含在项目中的呢,其实,如果你打开.csproject文件就会看到,通过将该文件添加到<Protobuf>的ItemGroup中即可,如下所示:
<ItemGroup> <Protobuf Include="..\Protos\*.proto" GrpcServices="Server" /> <Content Include="@(Protobuf)" LinkBase="" /> </ItemGroup>
C#对.proto文件的工具支持
工具包Grpc.Tools 被用来从.proto文件生成C#文件。生成的资产(文件)具有如下特性:
每次构建项目时都会根据需要进行生成。
生成的文件不会被添加到项目或签入源代码管理。
生成的C#文件是包含在OBJ目录。
服务器和客户端项目都需要此包。Grpc.Tools可以通过在VisualStudio中使用包管理器或添加<PackageReference>到项目文件:
XML复制
<PackageReference Include="Grpc.Tools" Version="1.19.0-pre1" PrivateAssets="All" />
工具包在运行时并不是必需的,因此,应该用PrivateAssets="All".
Services 文件夹中的具体的gRPC服务
我们知道Grpc.Tools工具包将根据.proto文件的定义翻译并生成对应的C#类型的文件。
对于服务器端资产,将生成一个抽象的服务基类型。基类型包含在.proto文件中包含的所有GRPC调用的定义。然后,您将创建从此基类型派生的具体服务实现,并实现GRPC调用的逻辑。对于前面描述的greet.proto示例,将生成包含虚拟SayHello方法的抽象GreeterBase类型。具体的实现GreeterService重写该方法并实现处理GRPC调用的逻辑。
正如HelloGrpc.Server项目中的Services\GreeterService.cs中的代码
public class GreeterService : Greeter.GreeterBase { public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context) { return Task.FromResult(new HelloReply { Message = "Hello " + request.Name }); } }
对于客户端,将生成一个具体的客户端类型中的GRPC调用。.proto文件被转换为可以调用的具体类型上的方法。为greet.proto前面描述的示例,一个具体的GreeterClient类型生成。这个GreeterClient类型包含SayHello方法,可以调用该方法来启动对服务器的GRPC调用。
public class Program { static async Task Main(string[] args) { // Include port of the gRPC server as an application argument var port = args.Length > 0 ? args[0] : "50051"; var channel = new Channel("localhost:" + port, ChannelCredentials.Insecure); var client = new Greeter.GreeterClient(channel); var reply = await client.SayHelloAsync( new HelloRequest { Name = "GreeterClient" }); Console.WriteLine("Greeting: " + reply.Message); await channel.ShutdownAsync(); Console.WriteLine("Press any key to exit..."); Console.ReadKey(); } }
默认情况下,分别生成服务器和客户端资产。.proto文件包含在<Protobuf>项目组。若要确保仅在服务器项目中生成服务器资产,GrpcServices属性设置为Server.
XML复制
<ItemGroup> <Protobuf Include="..\Protos\*.proto" GrpcServices="Server" /> <Content Include="@(Protobuf)" LinkBase="" /> </ItemGroup>
类似地,属性设置为Client在仅在客户项目中生成。
Startup
在Startup中我们发现跟普通的ASP.NET Core程序有所不同,具体的如下图所示:在ConfigureServices 服务中引入了gRPC服务,然后在Configure加入了路由
而这里需要引入三个与gRPC相关的nuget包
这里需要说明的是
ASP.NET Core 中间件和功能共享路由管道,因此可以将应用程序配置为服务其他请求处理程序。其他请求处理程序(如MVC控制器)可以与配置的GRPC服务路由并行工作。
其他需要说明的内容
与ASP.NET Core 接口的集成
GRPC服务可以完全访问ASP.NETCore功能,如依赖注入(Di)和日志功能。例如,服务实现可以通过构造函数解析DI容器中的记录器服务:
public class GreeterService : Greeter.GreeterBase { public GreeterService(ILogger<GreeterService> logger) { } }
默认情况下,GRPC服务可以解析具有任意生存期的其他DI服务(Singleton, Scoped, or Transient)。
在GRPC方法中解析HttpContext
GRPC 应用程序接口提供对某些HTTP/2消息数据的访问,例如method, host, header, and trailers。访问是通过ServerCallContext参数传递给每个GRPC方法: