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. Linux服务器磁盘空间占用情况分析与清理指南

    为确保重大节日期间,团队负责的测试环境服务器磁盘不会占用过高,导致频繁报警.我们要求在重大节假日前对服务器磁盘占用情况进行检查.如果发现占用过高,则需人为介入,进行相应清理. 一.检查要求 查看各分区 ...

  2. 一款基于Uniapp开发的开源低代码平台

    rtvue-lowcode低代码开发平台 rtvue-lowcode一款基于uniapp框架和uview组件库的低代码开发平台,项目提供可视化拖拽编辑器,采用MIT开源协议,适用于app.小程序等项目 ...

  3. Resource Acquisition Is Initialization

    在 C++ 中,资源获取即初始化(RAII, Resource Acquisition Is Initialization)是一种管理资源的编程惯用法.其核心思想是将资源的获取和释放绑定到对象的生命周 ...

  4. 逆向WeChat(七)

    上篇介绍了如何通过嗅探MojoIPC抓包小程序的HTTPS数据. 本篇逆向微信客户端本地数据库相关事宜. 本篇在博客园地址https://www.cnblogs.com/bbqzsl/p/184235 ...

  5. CNN每层卷积结果视觉展示(3Dircadb肝脏数据为例)

    试着展示了肝脏每层卷积之后的结果.代码如下: import torch import torch.nn as nn import SimpleITK as sitk import numpy as n ...

  6. 云原生周刊:DevOps-resources

    推荐一个 GitHub 仓库 "DevOps-resources".这个 GitHub 仓库包含了学习和实践 DevOps 所需的资源列表.它包括涉及云计算.容器化.微服务.自动化 ...

  7. 自学PHP笔记(四) PHP变量和常量

    PHP中变量有普通变量.可变变量和预定义变量,而常量就是普通变量和预定义变量. 1. 变量 在PHP中变量是内存中得一个命名单元,在系统中为程序中每个变量都分配一个存储单元,在这些存储单元中可以存储任 ...

  8. 顶点着色网格转换为 UV 映射的纹理化网格

    简介 顶点着色是一种将颜色信息直接应用于网格顶点的简便方法.这种方式常用于生成式 3D 模型的构建,例如 InstantMesh.然而,大多数应用程序更偏好使用 UV 映射的纹理化网格. 本教程将介绍 ...

  9. 结构体(C语言)

    目录 1. 结构体类型的声明 1.1 结构体回顾 1.1.1 结构的声明 1.1.2 结构体变量的创建和初始化 1.2 结构的特殊声明 1.3 结构的自引用 2. 结构体内存对齐 2.1 对齐规则 2 ...

  10. DB GPT本地安装部署

    源码下载 git clone https://github.com/eosphoros-ai/DB-GPT.git Miniconda环境安装 Miniconda 安装 mkdir -p ~/mini ...