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>

这里设置了 GrpcServicesClinet,所以,将会生成名称为 GrpcBasket.Basket.BasketClient 的类型。在 Web.Shopping.HttpAggregator.csprojMobile.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 服务定义与实现的更多相关文章

  1. 在.NET Core中批量注入Grpc服务

    GRPC 是谷歌发布的一个开源.高性能.通用RPC服务,尽管大部分 RPC 框架都使用 TCP 协议,但其实 UDP 也可以,而 gRPC 干脆就用了 HTTP2.还有就是它具有跨平台.跨语言 等特性 ...

  2. 如何在 Knative 中部署 WebSocket 和 gRPC 服务?

    作者 | 冬岛  阿里云容器平台工程师 导读:虽然说 Knative 默认就支持 WebSocket 和 gRPC,但在使用中会发现,有时想要把自己的 WebSocket 或 gRPC 部署到 Kna ...

  3. 使用Node.JS访问Hyperledger Fabric的gRPC服务

    在即将正式发布的Hyperledger Fabric SDK 1.0中,Hyperledger Fabric通过gRPC提供服务接口以取代现有的REST API.本文介绍了如何使用Node.JS访问H ...

  4. 用Java开发gRPC服务的例子分析

    本文的代码例子来自:https://github.com/grpc/grpc-java  定义服务 这一步与其他语言完全一样,需要定义gRPC的服务.方法.request和response的类型. 完 ...

  5. ASP.NET Core 3.0 上的gRPC服务模板初体验(多图)

    早就听说ASP.NET Core 3.0中引入了gRPC的服务模板,正好趁着家里电脑刚做了新系统,然后装了VS2019的功夫来体验一把.同时记录体验的过程.如果你也想按照本文的步骤体验的话,那你得先安 ...

  6. .NET Core微服务之路:基于gRPC服务发现与服务治理的方案

    重温最少化集群搭建,我相信很多朋友都已经搭建出来,基于Watch机制也实现了出来,相信也有很多朋友有了自己的实现思路,但是,很多朋友有个疑问,我API和服务分离好了,怎么通过服务中心进行发现呢,这个过 ...

  7. gRPC初探——概念介绍以及如何构建一个简单的gRPC服务

    目录 引言 1. gRPC简介 2. 使用Protocol Buffers进行服务定义 2.1 定义消息 2.2 定义服务接口 3.构建简单的gRPC服务 3.1 编写proto文件,定义消息和接口 ...

  8. python与consul 实现gRPC服务注册-发现

    背景 通过对gRPC的介绍我们知道,当正常启动服务后,我们只需要知道ip,port就可以进行gRPC的连接.可以想到,这种方式并不适合用于线上环境,因为这样直连的话就失去了扩展性,当需要多机部署的时候 ...

  9. .NET Core 3.0中用 Code-First 方式创建 gRPC 服务与客户端

    .NET Core love gRPC 千呼万唤的 .NET Core 3.0 终于在 9 月份正式发布,在它的众多新特性中,除了性能得到了大大提高,比较受关注的应该是 ASP.NET Core 3. ...

  10. python golang中grpc 使用示例代码详解

    python 1.使用前准备,安装这三个库 pip install grpcio pip install protobuf pip install grpcio_tools 2.建立一个proto文件 ...

随机推荐

  1. USB总线-Linux内核USB3.0设备控制器中断处理程序分析(九)

    1.概述 USB设备枚举.请求处理.数据交互都涉及USB设备控制器中断.当有事件发生时,USB设备控制器首先将事件信息通过DMA写入到事件缓冲区中,然后向CPU发出中断,随后CPU调用中断处理函数开始 ...

  2. 2021年6月国产数据库排行榜:OceanBase、PolarDB会师TiDB、openGauss,入局开源阵营,逐鹿生态建设

    "首夏犹清和,芳草亦未歇",时至六月,百花齐放.百家争鸣的国产数据库市场依旧延续着如骄阳般火热的态势.不过从最新一期的 国产数据库流行度排行榜 Top 10 中不难发现,一个词足以 ...

  3. day15-三大基本结构

    顺序结构 Java的基本结构就是顺序结构,除非特别指明,否则就按照顺序一句一句执行. 顺序结构是最简单的算法结构. 语句和语句之间,框与框之间是按从上到下的顺序进行的,它是由若干个依次执行的处理步骤组 ...

  4. 基于 KubeSphere 的应用容器化在智能网联汽车领域的实践

    公司简介 某国家级智能网联汽车研究中心成立于 2018 年,是担当产业发展咨询与建议.共性技术研发中心.创新成果转化的国家级创新平台,旨在提高我国在智能网联汽车及相关产业在全球价值链中的地位. 目前着 ...

  5. Nuxt.js 应用中的 app:templatesGenerated 事件钩子详解

    title: Nuxt.js 应用中的 app:templatesGenerated 事件钩子详解 date: 2024/10/19 updated: 2024/10/19 author: cmdra ...

  6. OKR 目标和关键成果

    OKR(Objectives and Key Results)是目标与关键成果管理法,是一套明确和跟踪目标及其完成情况的管理工具和方法.1.OKR首先是沟通工具:团队中的每个人都要写OKR,所有这些O ...

  7. JavaScript初始化对象数组

    一.{} 我们都知道JavaScript的数据结构是松散的,比如说你定义一个变量 var temp; 那么你可以随手这样定义temp.attr1 =  "参数1",因为对于Java ...

  8. 『玩转Streamlit』--页面布局

    一个优秀的数据应用不仅仅是功能的强大,更在于其用户体验的打造. 而良好的页面布局,作为用户体验的重要组成部分,不仅能够提升信息的可读性,还能引导用户高效地完成操作. 反之,混乱的布局会让人感到困惑和挫 ...

  9. 微信小程序目录结构

    一.小程序框架 微信开放平台--小程序框架介绍 小程序的目录结构很清晰,主要由描述整体内容的app和描述具体页面的page组成.一般来说,习惯对小程序的目录结构进行更加清晰的规划,例如将程序种会用到的 ...

  10. 查看Mysql数据库数据量大小、表大小、索引大小

    通过MySQL的information_schema数据库,可查询数据库中每个表占用的空间.表记录的行数: 该库中有一个TABLES表,这个表主要字段分别是: TABLE_SCHEMA:数据库名 TA ...