早就听说 ASP.NET Core 3.0 中引入了 gRPC 的服务模板, 正好趁着家里电脑刚做了新系统, 然后装了 VS2019 的功夫来体验一把. 同时记录体验的过程. 如果你也想按照本文的步骤体验的话, 那你得先安装. NET Core3.0 预览版的 SDK. 至于开发工具我用的时 VS2019, 当然你也可以使用 VS Code 进行.
gRPC 的简单介绍
gRPC https://grpc.io/docs/guides/ 是一种与语言无关的高性能远程过程调用 (RPC) 框架. 有关 gRPC 基础知识的详细信息, 请参阅 gRPC 文档页 https://grpc.io/docs/ .
gRPC 的主要优点是:
现代高性能轻量级 RPC 框架.
协定优先 API 开发, 默认使用协议缓冲区, 允许与语言无关的实现.
可用于多种语言的工具, 以生成强类型服务器和客户端.
支持客户端, 服务器和双向流式处理调用.
使用 Protobuf 二进制序列化减少对网络的使用.
这些优点使 gRPC 适用于:
效率至关重要的轻量级微服务.
需要多种语言用于开发的 Polyglot 系统.
需要处理流式处理请求或响应的点对点实时服务.
ASP.NET Core 3.0 上 gRPC 服务模板初体验
创建 gRPC 服务
打开 VS2019 从 Visual Studio"文件" 菜单中选择 "新建"> "项目".(由于我是新打开的 VS, 所以按照如下图所示创建新项目)
如下图所示, 选择创建《ASP.NET Core web 应用程序》, 然后点击下一步
在此页面按照下图所示, 输入项目名称, 位置, 解决方案名称, 然后点击右下角的 "创建" 按钮进行创建.
你以为上述步骤中点击 "创建" 就结束了嘛? 说好的要创建 gRPC 服务模板的, 所以, 点击上面的创建后会弹出如下图所示, 让你选择服务模板的窗口, 这里按照下图所示选择 gRPC 服务模板, 然后再次点击右下角的创建, 才是真正的创建项目.
创建成功后, 会出现如下图所示的项目结构
至此, 我们就创建好了一个 gRPC 服务的模板, 接下来我们先测试一番, 然后再好好的看下这个模板的结构吧
测试 gRPC 服务
首先打开 HelloGrpc.Server 这个服务端的工作目录, 然后 Shift + 鼠标右键弹出如下图所示的右键菜单, 如图所示打开 ps 窗口
输入 dotnet run 命令运行此 gRPC 服务端项目, 如下图所示, 说明服务端启动正常, 并开始监听对应的端口.
同样的方法, 我们启动客户端, 这时候客户端会向该服务端发送一条包含具有其名称 "GreeterClient" 的消息的问候信息. 该服务端将发送一条消息 "Hello GreeterClient" 作为响应, 并显示在命令提示符中. 如下图所示:
至此, gRPC 服务模板创建的服务端以及客户端测试成功. 下面我们就好好的探究一下这个服务模板吧.
gRPC 模板解析
在 HelloGrpc.Server 服务的端项目中有如下几个文件
greet.proto:greet.proto 文件定义 Greeter gRPC, 且用于生成 gRPC 服务器资产.
Services 文件夹: 包含 Greeter 服务的实现.
appSettings.JSON: 包含配置数据, 如 Kestrel 使用的协议.(熟悉 ASP.NET Core 的你一定很熟悉)
Program.cs: 包含 gRPC 服务的入口点.(熟悉 ASP.NET Core 的你一定很熟悉)
Startup.cs:IWebHostBuilder 的启动配置文件, 包含配置应用行为的代码.(熟悉 ASP.NET Core 的你一定很熟悉)
gRPC 客户端 HelloGrpc.Client 文件:
Program.cs 包含 gRPC 客户端的入口点和逻辑.
下面我们再打开每个文件看看里面究竟是什么东东吧.
proto 文件
proto
GRPC 使用约定优先的 API 开发方法. 默认情况下, 使用协议缓冲区 (Protobuf) 作为接口设计语言(IDL). 这个. proto 文件包含:
GRPC 服务的定义.
在客户端和服务器之间发送的消息.
有关 Protobuf 文件语法的更多信息, 请参见正式文件(原型).
如我们模板中创建的 greet.proto 文件内容如下:
- 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 文件的工具支持
工具包 https://www.nuget.org/packages/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 包
https://www.nuget.org/packages/Google.Protobuf/ 对于 Protobuf 消息 API.
https://www.nuget.org/packages/Grpc.Tools/
这里需要说明的是
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 方法:
- public class GreeterService : Greeter.GreeterBase
- {
- public override Task<HelloReply>
- SayHello(HelloRequest request, ServerCallContext context)
- {
- return Task.FromResult(new HelloReply
- {
- Message = "Hello" + request.Name
- });
- }
- }
ServerCallContext 不提供对所有 ASP.NET 接口中 HttpContext 的完全访问. GetHttpContext 扩展方法提供对表示 ASP.NET API 中底层 HTTP/2 消息的 httpContext 的完全访问:
- public class GreeterService : Greeter.GreeterBase
- {
- public override Task<HelloReply> SayHello(HelloRequest request,
- ServerCallContext context)
- {
- var httpContext = context.GetHttpContext();
- return Task.FromResult(new HelloReply
- {
- Message = "Using https:" + httpContext.Request.IsHttps
- });
- }
- }
请求体数据速率限制
默认情况下, Kestrel 服务器设置为最小请求主体数据速率. 对于客户端流式和双工流式的请求, 此速率可能不满足, 并且连接可能超时. 当 GRPC 服务包括客户端流和双工流调用时, 必须禁用最小请求正文数据速率限制:
- public class Program
- {
- public static void Main(string[] args)
- {
- CreateHostBuilder(args).Build().Run();
- }
- public static IHostBuilder CreateHostBuilder(string[] args) =>
- Host.CreateDefaultBuilder(args)
- .ConfigureWebHostDefaults(webBuilder =>
- {
- webBuilder.UseStartup<Startup>();
- webBuilder.ConfigureKestrel((context, options) =>
- {
- options.Limits.MinRequestBodyDataRate = null;
- });
- });
- }
参考文章
- gRPC services with C#
- Tutorial: Get started with gRPC in ASP.NET Core
- gRPC services with ASP.NET Core
- Migrating gRPC services from C-core to ASP.NET Core
总结
今天分享的内容有点多, 目的就是使记录尽可能的详细, 尽可能用通俗易懂的语言来进行描述, 让大家能用起来. 在 ASP.NET core3.0 中把 grpc 服务作为第一等公民进行支持, 所以我们有必要进行下了解. 可能很多朋友会有疑问了, 我 Web API 用的爽歪歪, 干嘛还要用 gRPC 这种远程过程调用协议啊. 关于这个问题, 我准备再单独开一篇文章进行讲解, 最后感谢大家的阅读, 码字不易, 多多推荐支持吧!
来源: https://www.cnblogs.com/yilezhu/p/10631420.html