前言:

 上一篇文章中简单的对gRPC进行了简单了解,并实现了gRPC在ASP.NET Core中服务实现、客户端调用;那么本篇继续对gRPC的4中服务方法定义、其他使用注意点进一步了解学习

一、gRPC的4类服务方法

  • 简单 RPC(一元方法):客户端向服务器发送单个请求并获得单个响应,就像普通的函数调用一样。

   示例:

rpc UnaryCall(ExampleRequest) returns (ExampleResponse) {}
  • 服务器端流式 RPC: 客户端发送请求到服务器,拿到一个流去读取返回的消息序列。 客户端读取返回的流,直到里面没有任何消息。通过在 响应 类型前插入 stream 关键字,可以指定一个服务器端的流方法

   示例:

rpc StreamingFromServer(ExampleRequest) returns (stream ExampleResponse) {}
  • 客户端流式 RPC: 

   示例:

rpc StreamingFromClient(stream ExampleRequest) returns (ExampleResponse) {}
  • 双向流式 RPC:双方使用读写流去发送一个消息序列。两个流独立操作,因此客户端和服务器可以以任意喜欢的顺序读写:

   比如, 服务器可以在写入响应前等待接收所有的客户端消息,或者可以交替的读取和写入消息,或者其他读写的组合。 每个流中的消息顺序被预留。你可以通过在请求和响应前加 stream 关键字去制定方法的类型。

   示例:

 rpc StreamingBothWays(stream ExampleRequest) returns (stream ExampleResponse) {}

  完整protos如下:

syntax = "proto3";
option csharp_namespace = "GrpcServiceDemo";
//可添加版本号区分v1/v2
package serviceTypeDemo;
//服务类型Demo:用于展现gRpc四种服务方法
service ServiceTypeDemo {
// Unary:一元方法
rpc UnaryCall (ExampleRequest) returns (ExampleResponse);
// Server streaming:服务流
rpc StreamingFromServer (ExampleRequest) returns (stream ExampleResponse);
// Client streaming:客户端流
rpc StreamingFromClient (stream ExampleRequest) returns (ExampleResponse);
// Bi-directional streaming:双向流
rpc StreamingBothWays (stream ExampleRequest) returns (stream ExampleResponse);
}
//请求对象
message ExampleRequest {
int32 pageIndex = 1;
int32 pageSize = 2;
bool isDescending = 3;
}
//响应对象
message ExampleResponse{
object result = 1;
int32 total = 2;
}

  服务实现:实现相对简单,主要展示读取流和写入流  

public class ServerTypeService : ServiceTypeDemo.ServiceTypeDemoBase
{
public override Task<ExampleResponse> UnaryCall(ExampleRequest request, ServerCallContext context)
{
ExampleResponse resp = GetResp();
return Task.FromResult(resp);
}
private static ExampleResponse GetResp()
{
var resp = new ExampleResponse();
resp.Total = new Random().Next(1, 20);
resp.Result.Add("abc");
resp.Result.Add("efg");
return resp;
}
public async override Task StreamingFromServer(ExampleRequest request, IServerStreamWriter<ExampleResponse> responseStream, ServerCallContext context)
{
var responses = new List<ExampleResponse>();
responses.Add(GetResp());
responses.Add(GetResp());
responses.Add(GetResp());
foreach (var response in responses)
{
//写入流中
await responseStream.WriteAsync(response);
}
}
public async override Task<ExampleResponse> StreamingFromClient(IAsyncStreamReader<ExampleRequest> requestStream, ServerCallContext context)
{
int pointCount = 0;
//读取传入流
while (await requestStream.MoveNext())
{
var point = requestStream.Current;
pointCount++;
}
var info = GetResp();
info.Total = pointCount;
return info;
}
public async override Task StreamingBothWays(IAsyncStreamReader<ExampleRequest> requestStream, IServerStreamWriter<ExampleResponse> responseStream, ServerCallContext context)
{
//读取内容
while (await requestStream.MoveNext())
{
var note = requestStream.Current;
var responses = new List<ExampleResponse>();
responses.Add(GetResp());
responses.Add(GetResp());
//循环写入
foreach (var prevNote in responses){
await responseStream.WriteAsync(prevNote);
}
}
}
}

二、gRPC其他注意点  

 1、截止时间和取消处理

    截止时间功能让 gRPC 客户端可以指定等待调用完成的时间。 超过截止时间时,将取消调用。

   截止时间配置:

  • 在进行调用时,使用 CallOptions.Deadline 配置截止时间。
  • 没有截止时间默认值。 gRPC 调用没有时间限制,除非指定了截止时间。
  • 截止时间指的是超过截止时间的 UTC 时间。 例如,DateTime.UtcNow.AddSeconds(5) 是从现在起 5 秒的截止时间。
  • 如果使用的是过去或当前的时间,则调用将立即超过截止时间。
  • 截止时间随 gRPC 调用发送到服务,并由客户端和服务独立跟踪。 gRPC 调用可能在一台计算机上完成,但当响应返回给客户端时,已超过了截止时间。

如果超过了截止时间,客户端和服务将有不同的行为:

  • 客户端将立即中止基础的 HTTP 请求并引发 DeadlineExceeded 错误。 客户端应用可以选择捕获错误并向用户显示超时消息。
  • 在服务器上,将中止正在执行的 HTTP 请求,并引发 ServerCallContext.CancellationToken。 尽管中止了 HTTP 请求,gRPC 调用仍将继续在服务器上运行,直到方法完成。 将取消令牌传递给异步方法,使其随调用一同被取消,这非常重要。例如,向异步数据库查询和 HTTP 请求传递取消令牌。 传递取消令牌让取消的调用可以在服务器上快速完成,并为其他调用释放资源。

   使用方式如下:

var defaultMethodConfig = new MethodConfig
{
Names = { MethodName.Default },
RetryPolicy = new RetryPolicy
{
//最大重试5次
MaxAttempts = 5,
//重试尝试之间的初始退避延迟。
InitialBackoff = TimeSpan.FromSeconds(1),
//最大退避会限制指数退避增长的上限。
MaxBackoff = TimeSpan.FromSeconds(5),
//每次重试尝试后,退避将乘以该值,并将在乘数大于 1 的情况下以指数方式增加。
BackoffMultiplier = 1.5,
//状态代码的集合,在此集合中重试
RetryableStatusCodes = { StatusCode.Unavailable }
}
};
//初始化Grpc通道:参数为gRPC服务地址
using var channel = GrpcChannel.ForAddress("https://localhost:5001", new GrpcChannelOptions()
{
ThrowOperationCanceledOnCancellation = true,
//设置重试:v2.36版本添加
ServiceConfig = new ServiceConfig() { MethodConfigs = { defaultMethodConfig } }
}); string token = string.Empty;
var client = new Greeter.GreeterClient(channel);
//设置超时5秒;headers:可传递头信息:如认证串
Metadata metadata = new Metadata();
metadata.Add("Authorization", $"Bearer {token}");
var reply = client.SayHello(new HelloRequest { Name = "GreeterClient" },
headers: metadata,
deadline: DateTime.UtcNow.AddSeconds(5));

 2、gRPC-Web应用

   gRPC-Web 允许浏览器 JavaScript 和 Blazor 应用调用 gRPC 服务。 无法从基于浏览器的应用中调用 HTTP/2 gRPC 服务。 可将托管于 ASP.NET Core 中的 gRPC 服务配置为随 HTTP/2 gRPC 一起支持 gRPC-Web。

  有两种方式可将 gRPC-Web 添加到 ASP.NET Core 应用中:

  • 在 ASP.NET Core 中同时支持 gRPC-Web 和 gRPC HTTP/2。 此选项会使用 Grpc.AspNetCore.Web 包提供的中间件。
  • 使用 Envoy 代理的 gRPC-Web 支持将 gRPC-Web 转换为 gRPC HTTP/2。 转换后的调用随后会转发给 ASP.NET Core 应用。

  a)添加Grpc.AspNetCore.Web 包引用

  b)修改Startup.cs文件如下:

public void ConfigureServices(IServiceCollection services){
services.AddGrpc();
}
public void Configure(IApplicationBuilder app){
app.UseRouting();
app.UseGrpcWeb();//启用gRPCWeb
app.UseEndpoints(endpoints =>
{
endpoints.MapGrpcService<GreeterService>().EnableGrpcWeb();
});
}

  c)Cors跨域设置:

public void ConfigureServices(IServiceCollection services)
{
services.AddGrpc();
services.AddCors(o => o.AddPolicy("AllowAll", builder =>
{
builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
.WithExposedHeaders("Grpc-Status", "Grpc-Message", "Grpc-Encoding", "Grpc-Accept-Encoding"
);
}));

}
public void Configure(IApplicationBuilder app)
{
app.UseRouting();
app.UseGrpcWeb();
app.UseCors();
app.UseEndpoints(endpoints =>{
endpoints.MapGrpcService<GreeterService>().EnableGrpcWeb()
.RequireCors("AllowAll");
});
} 

 3、gRPC进程间调用:需要.NET 5;

  服务端设置:   

public static readonly string SocketPath = Path.Combine(Path.GetTempPath(), "socket.tmp");

public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
webBuilder.ConfigureKestrel(options =>
{
if (File.Exists(SocketPath))
{
File.Delete(SocketPath);
}
options.ListenUnixSocket(SocketPath);
});
});

  客户端设置:  

public class UnixDomainSocketConnectionFactory
{
private readonly EndPoint _endPoint; public UnixDomainSocketConnectionFactory(EndPoint endPoint)
{
_endPoint = endPoint;
} public async ValueTask<Stream> ConnectAsync(SocketsHttpConnectionContext _,
CancellationToken cancellationToken = default)
{
var socket = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.Unspecified); try
{
await socket.ConnectAsync(_endPoint, cancellationToken).ConfigureAwait(false);
return new NetworkStream(socket, true);
}
catch
{
socket.Dispose();
throw;
}
}
}

    在创建通道连接时:

public static readonly string SocketPath = Path.Combine(Path.GetTempPath(), "socket.tmp");

public static GrpcChannel CreateChannel()
{
var udsEndPoint = new UnixDomainSocketEndPoint(SocketPath);
var connectionFactory = new UnixDomainSocketConnectionFactory(udsEndPoint);
var socketsHttpHandler = new SocketsHttpHandler
{
ConnectCallback = connectionFactory.ConnectAsync
}; return GrpcChannel.ForAddress("http://localhost", new GrpcChannelOptions
{
HttpHandler = socketsHttpHandler
});
}

 4、相关配置项:

  服务端:

  gRPC 服务在 Startup.cs 中使用 AddGrpc 进行配置。

选项 默认值 描述
MaxSendMessageSize null 可以从服务器发送的最大消息大小(以字节为单位)。 尝试发送超过配置的最大消息大小的消息会导致异常。 设置为 null时,消息的大小不受限制。
MaxReceiveMessageSize 4 MB 可以由服务器接收的最大消息大小(以字节为单位)。 如果服务器收到的消息超过此限制,则会引发异常。 增大此值可使服务器接收更大的消息,但可能会对内存消耗产生负面影响。 设置为 null时,消息的大小不受限制。
EnableDetailedErrors false 如果为 true,则当服务方法中引发异常时,会将详细异常消息返回到客户端。 默认值为 false。 将 EnableDetailedErrors 设置为 true 可能会泄漏敏感信息。
CompressionProviders gzip 用于压缩和解压缩消息的压缩提供程序的集合。 可以创建自定义压缩提供程序并将其添加到集合中。 默认已配置提供程序支持 gzip 压缩。
ResponseCompressionAlgorithm null 压缩算法用于压缩从服务器发送的消息。 该算法必须与 CompressionProviders 中的压缩提供程序匹配。 若要使算法可压缩响应,客户端必须通过在 grpc-accept-encoding 标头中进行发送来指示它支持算法。
ResponseCompressionLevel null 用于压缩从服务器发送的消息的压缩级别。
Interceptors None 随每个 gRPC 调用一起运行的侦听器的集合。 侦听器按注册顺序运行。 全局配置的侦听器在为单个服务配置的侦听器之前运行。 有关 gRPC 侦听器的详细信息,请参阅 gRPC 侦听器与中间件
IgnoreUnknownServices false 如果为 true,则对未知服务和方法的调用不会返回 UNIMPLEMENTED 状态,并且请求会传递到 ASP.NET Core 中的下一个注册中间件。

  客户端:

   gRPC 客户端配置在 GrpcChannelOptions 中进行设置。 下表描述了用于配置 gRPC 通道的选项      

选项 默认值 描述
HttpHandler 新实例 用于进行 gRPC 调用的 HttpMessageHandler。 可以将客户端设置为配置自定义 HttpClientHandler,或将附加处理程序添加到 gRPC 调用的 HTTP 管道。 如果未指定 HttpMessageHandler,则会通过自动处置为通道创建新 HttpClientHandler 实例。
HttpClient null 用于进行 gRPC 调用的 HttpClient。 此设置是 HttpHandler 的替代项。
DisposeHttpClient false 如果设置为 true 且指定了 HttpMessageHandler 或 HttpClient,则在处置 GrpcChannel 时,将分别处置 HttpHandler 或 HttpClient
LoggerFactory null 客户端用于记录有关 gRPC 调用的信息的 LoggerFactory。 可以通过依赖项注入来解析或使用 LoggerFactory.Create 来创建 LoggerFactory 实例。 有关配置日志记录的示例,请参阅 .NET 上 gRPC 中的日志记录和诊断
MaxSendMessageSize null 可以从客户端发送的最大消息大小(以字节为单位)。 尝试发送超过配置的最大消息大小的消息会导致异常。 设置为 null时,消息的大小不受限制。
MaxReceiveMessageSize 4 MB 可以由客户端接收的最大消息大小(以字节为单位)。 如果客户端收到的消息超过此限制,则会引发异常。 增大此值可使客户端接收更大的消息,但可能会对内存消耗产生负面影响。 设置为 null时,消息的大小不受限制。
Credentials null 一个 ChannelCredentials 实例。 凭据用于将身份验证元数据添加到 gRPC 调用。
CompressionProviders gzip 用于压缩和解压缩消息的压缩提供程序的集合。 可以创建自定义压缩提供程序并将其添加到集合中。 默认已配置提供程序支持 gzip 压缩。
ThrowOperationCanceledOnCancellation false 如果设置为 true,则在取消调用或超过其截止时间时,客户端将引发 OperationCanceledException
MaxRetryAttempts 5 最大重试次数。 该值限制服务配置中指定的任何重试和 hedging 尝试值。单独设置该值不会启用重试。 重试在服务配置中启用,可以使用 ServiceConfig 来启用。 null 值会删除最大重试次数限制。 有关重试的更多详细信息,请参阅“暂时性故障处理与 gRPC 重试”。
MaxRetryBufferSize 16 MB 在重试或 hedging 调用时,可用于存储发送的消息的最大缓冲区大小(以字节为单位)。 如果超出了缓冲区限制,则不会再进行重试,并且仅保留一个 hedging 调用,其他 hedging 调用将会取消。 此限制将应用于通过通道进行的所有调用。 值 null 移除最大重试缓冲区大小限制。
MaxRetryBufferPerCallSize 1 MB 在重试或 hedging 调用时,可用于存储发送的消息的最大缓冲区大小(以字节为单位)。 如果超出了缓冲区限制,则不会再进行重试,并且仅保留一个 hedging 调用,其他 hedging 调用将会取消。 此限制将应用于一个调用。 值 null 移除每个调用的最大重试缓冲区大小限制。
ServiceConfig null gRPC 通道的服务配置。 服务配置可以用于配置 gRPC 重试

参考:

 官方说明文档:https://grpc.io/docs/what-is-grpc/ 

 微软:https://docs.microsoft.com/zh-cn/aspnet/core/grpc/?view=aspnetcore-3.0

 示例源码地址:https://github.com/cwsheng/GrpcDemo

  

gRPC在 ASP.NET Core 中应用学习(二)的更多相关文章

  1. gRPC在 ASP.NET Core 中应用学习

    一.gRPC简介: gRPC 是一个由Google开源的,跨语言的,高性能的远程过程调用(RPC)框架. gRPC使客户端和服务端应用程序可以透明地进行通信,并简化了连接系统的构建.它使用HTTP/2 ...

  2. (12)ASP.NET Core 中的配置二(Configuration)

    1.内存配置 MemoryConfigurationProvider使用内存中集合作为配置键值对.若要激活内存中集合配置,请在ConfigurationBuilder的实例上调用AddInMemory ...

  3. IdentityServer4在Asp.Net Core中的应用(二)

    继续上次授权的内容,客户端模式后我们再说以下密码模式,先回顾下密码模式的流程: 我们还是使用上次的代码,在那基础上修改,在IdentityServer4里面有一个IdentityServer4.Tes ...

  4. (13)ASP.NET Core 中的选项模式(Options)

    1.前言 选项(Options)模式是对配置(Configuration)的功能的延伸.在12章(ASP.NET Core中的配置二)Configuration中有介绍过该功能(绑定到实体类.绑定至对 ...

  5. C# 嵌入dll 动软代码生成器基础使用 系统缓存全解析 .NET开发中的事务处理大比拼 C#之数据类型学习 【基于EF Core的Code First模式的DotNetCore快速开发框架】完成对DB First代码生成的支持 基于EF Core的Code First模式的DotNetCore快速开发框架 【懒人有道】在asp.net core中实现程序集注入

    C# 嵌入dll   在很多时候我们在生成C#exe文件时,如果在工程里调用了dll文件时,那么如果不加以处理的话在生成的exe文件运行时需要连同这个dll一起转移,相比于一个单独干净的exe,这种形 ...

  6. 3、带你一步一步学习ASP.NET Core中的配置之Configuration

    如果你是刚接触ASP.NET Core的学习的话,你会注意到:在ASP.NET Core项目中,看不到.NET Fraemwork时代中的web.config文件和app.config文件了.那么你肯 ...

  7. 学习ASP.NET Core Blazor编程系列二——第一个Blazor应用程序(中)

    学习ASP.NET Core Blazor编程系列一--综述 学习ASP.NET Core Blazor编程系列二--第一个Blazor应用程序(上) 四.创建一个Blazor应用程序 1. 第一种创 ...

  8. ASP.NET Core 中的那些认证中间件及一些重要知识点

    前言 在读这篇文章之间,建议先看一下我的 ASP.NET Core 之 Identity 入门系列(一,二,三)奠定一下基础. 有关于 Authentication 的知识太广,所以本篇介绍几个在 A ...

  9. [转]ASP.NET Core 中的那些认证中间件及一些重要知识点

    本文转自:http://www.qingruanit.net/c_all/article_6645.html 在读这篇文章之间,建议先看一下我的 ASP.NET Core 之 Identity 入门系 ...

随机推荐

  1. sketch 导出 svg

    sketch 导出 svg refs xgqfrms 2012-2020 www.cnblogs.com 发布文章使用:只允许注册用户才可以访问!

  2. TERSUS无代码开发(笔记09)-简单实例前端样式设计

    前端常用样式设计 =========================================================================================== ...

  3. Pygame基础(1)

    Pygame是Python的一个很常用的游戏框架,今天我来讲一讲Pygame的基础知识 Pygame的官网:https://www.pygame.org/news Pygame的下载 打开cmd输入p ...

  4. Error Code: 1366. Incorrect DECIMAL value: '0' for column '' at row -1 0.266 sec;

    Reference: https://stackoverflow.com/questions/35037288/incorrect-decimal-integer-value-mysql     Er ...

  5. Prometheus+Grafana+Alertmanager搭建全方位的监控告警系统

    prometheus安装和配置 prometheus组件介绍 1.Prometheus Server: 用于收集和存储时间序列数据. 2.Client Library: 客户端库,检测应用程序代码,当 ...

  6. python类的内部方法

    目录 一.绑定方法与非绑定方法 1.绑定方法 2.非绑定方法 二.property 1.什么是property? 2.为什么要用property? 3.如何使用property? 三.isinstan ...

  7. Go的数组

    目录 数组 一.数组的定义 1.声明数组 2.初始化设值 3.指定位置设值 4.不指定长度初始化(了解) 二.数组的使用 三.数组的类型 四.数组的长度 五.迭代数组 1.初始化迭代 2.使用rang ...

  8. Docker 搭建nexus私服

    一.概述 有三种专门的Maven仓库管理软件可以用来帮助大家建立私服:Apache基金会的Archiva.JFrog的Artifactory和Sonatype的Nexus.而Nexus是当前最流行的M ...

  9. 微信小程序滚动条设置

    隐藏滚动条 ::-webkit-scrollbar { width: 0rpx; height: 0rpx; background-color: transparent; } 其实设置为宽高为 0 或 ...

  10. Nginx配置翻译

    Windows 格式 server { listen 82; server_name localhost; root "D:/testfile/"; location / { in ...