eShopOnContainer 中 Grpc 服务定义与实现
eShopOnContainer 中 Grpc 服务定义与实现
服务于前端的后端 (BFF) 模式是 API 网关模式的一种变形,针对外部使用者的不同需求,为每种不同的客户端使用者提供一种后端 API,形成服务统一优雅的服务边界。
边界层封装内部服务的复杂性,为外部调用提供统一的外观表示。不同的外部使用者有着不同的使用需求,所以边界层的封装也会由于外部使用者的多样化,而出现多种形式。
Web.Shopping.HttpAggregator 是对内部服务进行封装之后,提供给 Web 层使用。
而 Mobile.Shopping.HttpAggregator 对内部服务进行封装之后,提供给 SPA 单页应用使用。
在 BFF 与实际的后端服务之间,使用了 Grpc 通讯协议来提高通讯效率。通讯协议的实际定义位于微服务中,在 BFF 中,通过引用 Grpc 协议定义文件来生成访问服务的 Grpc 客户端。而在微服务中,也通过这个通讯协议定义文件来完成实际的服务实现。最终完成 BFF 与微服务之间的通讯实现。
在下面的项目文件中,引入了 Grpc 的定义文件:
- src\ApiGateways\Web.Bff.Shopping\aggregator\Web.Shopping.HttpAggregator.csproj
- src\ApiGateways\Mobile.Bff.Shopping\aggregator\Mobile.Shopping.HttpAggregator.csproj
<ItemGroup>
<Protobuf Include="..\..\..\Services\Basket\Basket.API\Proto\basket.proto" GrpcServices="Client" />
<Protobuf Include="..\..\..\Services\Catalog\Catalog.API\Proto\catalog.proto" GrpcServices="Client" />
<Protobuf Include="..\..\..\Services\Ordering\Ordering.API\Proto\ordering.proto" GrpcServices="Client" />
</ItemGroup>
为了支持 Grpc,项目文件中引用了 Grpc 相关的 NuGet 包:
<PackageReference Include="Google.Protobuf" Version="3.15.0" />
<PackageReference Include="Grpc.AspNetCore.Server.ClientFactory" Version="2.34.0" />
<PackageReference Include="Grpc.Core" Version="2.34.0" />
<PackageReference Include="Grpc.Net.ClientFactory" Version="2.34.0" />
<PackageReference Include="Grpc.Tools" Version="2.34.0" PrivateAssets="All" />
以 src\Services\Basket\Basket.API\Proto\basket.proto
为例,其定义如下:
syntax = "proto3";
option csharp_namespace = "GrpcBasket";
package BasketApi;
service Basket {
rpc GetBasketById(BasketRequest) returns (CustomerBasketResponse) {}
rpc UpdateBasket(CustomerBasketRequest) returns (CustomerBasketResponse) {}
}
message BasketRequest {
string id = 1;
}
message CustomerBasketRequest {
string buyerid = 1;
repeated BasketItemResponse items = 2;
}
message CustomerBasketResponse {
string buyerid = 1;
repeated BasketItemResponse items = 2;
}
message BasketItemResponse {
string id = 1;
int32 productid = 2;
string productname = 3;
double unitprice = 4;
double oldunitprice = 5;
int32 quantity = 6;
string pictureurl = 7;
}
在 .NET 中,会忽略 package 语句,而使用 csharp_namespace 中定义的命名空间。
实现 Basket 服务端 Grpc 服务
在 Basket.API 项目中,定义了如下内容:
<ItemGroup>
<Protobuf Include="Proto\basket.proto" GrpcServices="Server" Generator="MSBuild:Compile" />
<Content Include="@(Protobuf)" />
<None Remove="@(Protobuf)" />
</ItemGroup>
其中的 GrpcServices
特性用来限制 C# 代码生成。 有效 GrpcServices 选项如下:
- 同时生成服务端定义和客户端代码(如果不存在 GrpcServices 属性定义,则为默认值)
- Server,只生成服务端定义,服务器端抽象接口定义会自动添加
Base
后缀 - Client,只生成客户端代码,客户端定义会自动添加
Client
后缀 - None,不生成
由于这里定义了 Server
,所以,在服务器端仅仅生成了服务定义的抽象接口 Basket.BasketBase
。
在 src\Services\Basket\Basket.API\Grpc\BasketService.cs 中,实现了 Grpc 服务端。
namespace GrpcBasket;
public class BasketService : Basket.BasketBase
{
private readonly IBasketRepository _repository;
private readonly ILogger<BasketService> _logger;
public BasketService(IBasketRepository repository, ILogger<BasketService> logger)
{
_repository = repository;
_logger = logger;
}
[AllowAnonymous]
public override async Task<CustomerBasketResponse> GetBasketById(BasketRequest request, ServerCallContext context)
服务端作为 ASP.NET Core,配置 Grpc 支持。
public virtual IServiceProvider ConfigureServices(IServiceCollection services)
{
// ...
services.AddGrpc(options =>
{
options.EnableDetailedErrors = true;
});
// ...
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory)
{
// ...
app.UseEndpoints(endpoints =>
{
endpoints.MapGrpcService<BasketService>();
// ...
}
使用 Basket 客户端
在 Web.Bff.Shopping/aggregator 项目中,也包含了 Grpc 定义的 protobuf 定义。
<ItemGroup>
<Protobuf Include="..\..\..\Services\Basket\Basket.API\Proto\basket.proto" GrpcServices="Client" />
<Protobuf Include="..\..\..\Services\Catalog\Catalog.API\Proto\catalog.proto" GrpcServices="Client" />
<Protobuf Include="..\..\..\Services\Ordering\Ordering.API\Proto\ordering.proto" GrpcServices="Client" />
</ItemGroup>
这里设置了 GrpcServices
为 Clinet
,所以,将会生成名称为 GrpcBasket.Basket.BasketClient
的类型。在 Web.Shopping.HttpAggregator.csproj
和 Mobile.Shopping.HttpAggregator.csproj
两个项目的 Startup.cs 中,可以看到对该类型的使用。
// Basket
public static IServiceCollection AddGrpcServices(this IServiceCollection services)
{
// grpc 的异常处理器
services.AddTransient<GrpcExceptionInterceptor>();
// basket
services.AddScoped<IBasketService, BasketService>();
services.AddGrpcClient<Basket.BasketClient>((services, options) =>
{
var basketApi = services.GetRequiredService<IOptions<UrlsConfig>>().Value.GrpcBasket;
options.Address = new Uri(basketApi);
}).AddInterceptor<GrpcExceptionInterceptor>();
// catalog
services.AddScoped<ICatalogService, CatalogService>();
services.AddGrpcClient<Catalog.CatalogClient>((services, options) =>
{
var catalogApi = services.GetRequiredService<IOptions<UrlsConfig>>().Value.GrpcCatalog;
options.Address = new Uri(catalogApi);
}).AddInterceptor<GrpcExceptionInterceptor>();
// ordering
services.AddScoped<IOrderingService, OrderingService>();
services.AddGrpcClient<OrderingGrpc.OrderingGrpcClient>((services, options) =>
{
var orderingApi = services.GetRequiredService<IOptions<UrlsConfig>>().Value.GrpcOrdering;
options.Address = new Uri(orderingApi);
}).AddInterceptor<GrpcExceptionInterceptor>();
return services;
};
而自定义的 BasketService
则封装了生成的 BasketClient
实现,其中主要完成了客户端数据表示到服务端数据表示的转换工作。
public class BasketService : IBasketService
{
private readonly Basket.BasketClient _basketClient;
private readonly ILogger<BasketService> _logger;
public BasketService(Basket.BasketClient basketClient, ILogger<BasketService> logger)
{
_basketClient = basketClient;
_logger = logger;
}
public async Task<BasketData> GetByIdAsync(string id)
{
_logger.LogDebug("grpc client created, request = {@id}", id);
var response = await _basketClient.GetBasketByIdAsync(new BasketRequest { Id = id });
_logger.LogDebug("grpc response {@response}", response);
return MapToBasketData(response);
}
注:这里似乎可以考虑使用 AutoMapper 来优化数据传输对象的转换。
eShopOnContainer 中 Grpc 服务定义与实现的更多相关文章
- 在.NET Core中批量注入Grpc服务
GRPC 是谷歌发布的一个开源.高性能.通用RPC服务,尽管大部分 RPC 框架都使用 TCP 协议,但其实 UDP 也可以,而 gRPC 干脆就用了 HTTP2.还有就是它具有跨平台.跨语言 等特性 ...
- 如何在 Knative 中部署 WebSocket 和 gRPC 服务?
作者 | 冬岛 阿里云容器平台工程师 导读:虽然说 Knative 默认就支持 WebSocket 和 gRPC,但在使用中会发现,有时想要把自己的 WebSocket 或 gRPC 部署到 Kna ...
- 使用Node.JS访问Hyperledger Fabric的gRPC服务
在即将正式发布的Hyperledger Fabric SDK 1.0中,Hyperledger Fabric通过gRPC提供服务接口以取代现有的REST API.本文介绍了如何使用Node.JS访问H ...
- 用Java开发gRPC服务的例子分析
本文的代码例子来自:https://github.com/grpc/grpc-java 定义服务 这一步与其他语言完全一样,需要定义gRPC的服务.方法.request和response的类型. 完 ...
- ASP.NET Core 3.0 上的gRPC服务模板初体验(多图)
早就听说ASP.NET Core 3.0中引入了gRPC的服务模板,正好趁着家里电脑刚做了新系统,然后装了VS2019的功夫来体验一把.同时记录体验的过程.如果你也想按照本文的步骤体验的话,那你得先安 ...
- .NET Core微服务之路:基于gRPC服务发现与服务治理的方案
重温最少化集群搭建,我相信很多朋友都已经搭建出来,基于Watch机制也实现了出来,相信也有很多朋友有了自己的实现思路,但是,很多朋友有个疑问,我API和服务分离好了,怎么通过服务中心进行发现呢,这个过 ...
- gRPC初探——概念介绍以及如何构建一个简单的gRPC服务
目录 引言 1. gRPC简介 2. 使用Protocol Buffers进行服务定义 2.1 定义消息 2.2 定义服务接口 3.构建简单的gRPC服务 3.1 编写proto文件,定义消息和接口 ...
- python与consul 实现gRPC服务注册-发现
背景 通过对gRPC的介绍我们知道,当正常启动服务后,我们只需要知道ip,port就可以进行gRPC的连接.可以想到,这种方式并不适合用于线上环境,因为这样直连的话就失去了扩展性,当需要多机部署的时候 ...
- .NET Core 3.0中用 Code-First 方式创建 gRPC 服务与客户端
.NET Core love gRPC 千呼万唤的 .NET Core 3.0 终于在 9 月份正式发布,在它的众多新特性中,除了性能得到了大大提高,比较受关注的应该是 ASP.NET Core 3. ...
- python golang中grpc 使用示例代码详解
python 1.使用前准备,安装这三个库 pip install grpcio pip install protobuf pip install grpcio_tools 2.建立一个proto文件 ...
随机推荐
- 智慧医院IT运维方案,全局网络态势感知
随着医疗卫生体制改革不断深化,卫生行业信息化应用不断普及,大数据.AI.医疗物联网等技术的应用,快速推动"智慧医院"建设.以HIS(医院信息系统).EMRS(电子病历系统).PAC ...
- placement new --特殊的内存分配
placement new 是 C++ 中的一种特殊的内存分配技术,用来在指定的内存地址上直接构造对象.与普通的 new 运算符不同,placement new 并不分配新的内存,而是在已经分配好的内 ...
- Go语言对接微信支付与退款全流程指南
目录: 一.准备工作 二.初始化微信支付客户端 三.实现支付功能 1. 付款时序图 2. 实现不同场景下的支付 WAP端支付 PC端支付 Android端支付 3. 解析支付回调 四.实现退款功能 退 ...
- Java日期时间API系列37-----时间段是否有重叠(交集)的计算方法
在日程安排或预约排期等场景中,经常会需要对比2个或多个时间段是重叠的功能,我经过整理和验证,发现了下面的算法比较好一些,分享一下. 1.只有2个时间段的情况 例如:存在区间A.区间B,重叠的情况很多, ...
- 02 Transformer 中 Add&Norm (残差和标准化)代码实现
python/pytorch 基础 https://www.cnblogs.com/nickchen121 培训机构(Django 类似于 Transformers) 首先由一个 norm 函数 no ...
- manim边做边学--有向图
有向图和上一篇介绍的无向图基本一样,唯一的区别在于有向图的边有方向性,它表示的是顶点之间的单向或依赖关系. 有向图G一般表示为:G=<V,E>.和无向图一样,V是顶点集合,E是边的集合. ...
- kotlin协程——>通道
通道:延期的值提供了⼀种便捷的⽅法使单个值在多个协程之间进⾏相互传输.通道提供了⼀种在流中传输 值的⽅法. 通道基础: ⼀个 Channel 是⼀个和 BlockingQueue ⾮常相似的概念.其中 ...
- 鲲鹏(ARM64)+麒麟(Kylin v10)离线部署 KubeSphere
作者:社区用户-天行1st 本文将详细介绍,如何基于鲲鹏 CPU(ARM64) 和操作系统 Kylin V10 SP2/SP3,利用 KubeKey 制作 KubeSphere 和 Kubernete ...
- 五分钟一百行代码,手写一个vue项目全局通用的toast提示组件
前言: 我们已经分享过如何快速实现自己需要的全局弹框组件: 在开发 Vue 项目时,特别是H5页面的项目,还有一个组件是我们非常常用的,它相对弹框来说没有那么大,并且不需要手动关闭在需要更简洁的提示用 ...
- 快速部署单服务器oracle12c
docker pull docker.io/truevoly/oracle-12c mkdir -p /usr/local/oracle/data_temp chmod 777 /usr/local/ ...