Abp vnext 微服务架构下集成 gRpc
- Abp vNext 集成 gRpc
- gRpc 服务端 : 微服务 IotHub
- 创建微服务
- 引用 gRpc 包
- 添加 *.proto 文件
- 修改项目文件
- 新建 gRpc 服务
- ApsNet Core 集成 gRpc
- 引用包
- 添加服务
- 添加 gRpc 服务 Endpoints
- 设置 gRpc 的端口
- gRpc客户端:微服务 IotEdge
- 创建微服务
- 引用包
- *.proto 文件
- 拷贝式
- 引用式
- 编写调用 gRpc 服务
- 服务接口
- 服务实现
- ApsNet Core 集成 gRpc
- 引用包
- 添加 gRpc 客户端
- 测试
- gRpc 服务端 : 微服务 IotHub
Abp vNext 集成 gRpc
为了演示,这里将创建两个微服务:
- Artisan.IotHub
- Artisan.IotEdge
项目层级目录
src ├── applications ├── modules ├── ... ├── services # 主目录 │ ├── iot-edge # iot-edge 微服务 │ │ ├── src # 代码 │ │ │ ├── Artisan.IotEdge.Application # 项目 │ │ │ └── ... │ │ ├── Artisan.IotEdge.sln # 解决方案 │ │ └── ... │ ├── iot-hub # iot-hub 微服务 │ │ ├── src # 代码 │ │ │ ├── Artisan.IotHub.Application # 项目 │ │ │ └── ... │ │ ├── Artisan.IotHub.sln # 解决方案 │ │ └── ... └── ...
re>gRpc 服务端 : 微服务 IotHub
创建微服务
创建微服务 IotHub
abp new Artisan.IotHub -u none -d ef -dbms SqlServer --separate-identity-server --version 5.2.1
re>引用 gRpc 包
项目【Artisan.IotHub.Application】引用 gRpc 服务端需要的包
re>
添加 *.proto 文件
在项目【Artisan.IotHub.Application】新建文件夹
Protos
, 然后在该文件夹下添加一个product.proto
文件,内容如下:代码清单: Artisan.IotHub.Application/Protos/product.proto
syntax = "proto3"; option csharp_namespace = "Artisan.IotHub.Grpc"; package IotHubApi; service ProductPublic { rpc GetById(ProductRequest) returns (ProductResponse); } message ProductRequest { string id = 1; } message ProductResponse { string id = 1; string name = 2; }
re>修改项目文件
右键项目【Artisan.IotHub.Application】的工程文件,在弹出的菜单中选择【编译项目文件】,添加如下内容:
re>
其中,
节点:
re>
是设置 gRpc 的服务文件,以便 grpc.tools 该文件自动生成服务端代码
节点:
re>
将
*.proto
文件的属性设置为:【内容】、【不复制】新建 gRpc 服务
在项目【Artisan.IotHub.Application】下新建文件夹
Grpc
, 在该文件夹下新建类PublicProductGrpcService
代码清单:Artisan.IotHub.Application/Grpc/PublicProductGrpcService.cs
using Grpc.Core; using System.Threading.Tasks; namespace Artisan.IotHub.Grpc { public class PublicProductGrpcService : ProductPublic.ProductPublicBase { public PublicProductGrpcService() { } public override async Task
re>GetById( ProductRequest request, ServerCallContext context) { return new ProductResponse { Id = request.Id, Name = "TestProduct" }; } } } 其中,
类 ProductPublic.ProductPublicBase 是由 grpc.tools 根据 product.proto 文件自动生成的。
如果没有自动生成,尝试编译项目【Artisan.IotHub.Application】
ApsNet Core 集成 gRpc
引用包
项目【Artisan.IotHub.HttpApi.Host】引入如下包:
re>
添加服务
代码清单:代码清单:Artisan.IotHub.HttpApi.Host/IotHubHttpApiHostModule.cs
public class IotHubHttpApiHostModule : AbpModule { public override void ConfigureServices(ServiceConfigurationContext context) { //...... ConfigureGrpc(context, configuration); } ///
re>/// 将 gRPC 服务添加到 ASP.NET Core 应用 /// https://docs.microsoft.com/zh-cn/aspnet/core/grpc/aspnetcore?view=aspnetcore-6.0&tabs=visual-studio /// /// aram> /// aram> private void ConfigureGrpc(ServiceConfigurationContext context, IConfiguration configuration) { context.Services.AddGrpc(options => { options.EnableDetailedErrors = true; }); } }添加 gRpc 服务 Endpoints
代码清单:代码清单:Artisan.IotHub.HttpApi.Host/IotHubHttpApiHostModule.cs
using Artisan.IotHub.Grpc; public class IotHubHttpApiHostModule : AbpModule { public override void OnApplicationInitialization(ApplicationInitializationContext context) { //...... app.UseConfiguredEndpoints(endpoints => { endpoints.MapGrpcService
re>(); }); } } 设置 gRpc 的端口
在配置文件
appsettings.json
中添加微服务IotHub的端口:{ "Kestrel": { "Endpoints": { "Http": { "Url": "http://localhost:7059", "Protocols": "Http1AndHttp2" //有些中间件走的还是http1.0,故要兼容 }, "Https": { "Url": "https://localhost:44359", "Protocols": "Http1AndHttp2" // 有些中间件走的还是http1.0,故要兼容 }, "gRPC": { "Url": "http://localhost:81", "Protocols": "Http2" // gRPC是基于Http2的,必须设置为Http2 } } }, // ...... }
re>特别注意:
gRPC 是基于 Http2的,而项目中的Http 和 Https ,有些功能还是基于 Http1.0的,
故需要通过配置节点:Protocols来分别设置它们的协议。
gRpc客户端:微服务 IotEdge
创建微服务
创建微服务 IotEdge
abp new Artisan.IotEdge -u none -d ef -dbms SqlServer --separate-identity-server --version 5.2.1
re>引用包
项目【Artisan.IotEdge.Application】引入如下包:
re>
*.proto 文件
拷贝式
可以将项目【 Artisan.IotHub.Application】下的
Artisan.IotHub.Application/Protos/product.proto
文件拷贝到项目【Artisan.IotEdge.Application】中,然后在项目【Artisan.IotEdge.Application】文件中添加:re>
注意:GrpcServices="Client" 是 Client,而不是:Server
但是这样做有点麻烦,当项目【 Artisan.IotHub.Application】的
Artisan.IotHub.Application/Protos/product.proto
文件修改了,还得拷贝一次,比较麻烦而且容易因为遗忘而出错。比较稳妥的做法是直接引用,而不是拷贝。引用式
通过引用的方式,添加
*.proto 文件
在项目【Artisan.IotEdge.Application】文件中添加:
re>
这样就不用拷贝项目【 Artisan.IotHub.Application】下的
Artisan.IotHub.Application/Protos/product.proto
文件了项目层级目录
src ├── applications ├── modules ├── ... ├── services # 主目录 │ ├── iot-edge # iot-edge 微服务 │ │ ├── src # 代码 │ │ │ ├── Artisan.IotEdge.Application # 项目 │ │ │ └── ... │ │ ├── Artisan.IotEdge.sln # 解决方案 │ │ └── ... │ ├── iot-hub # iot-hub 微服务 │ │ ├── src # 代码 │ │ │ ├── Artisan.IotHub.Application # 项目 │ │ │ │ ├── Protos │ │ │ │ │ ├── product.proto │ │ │ └── ... │ │ ├── Artisan.IotHub.sln # 解决方案 │ │ └── ... └── ...
re>编写调用 gRpc 服务
服务接口
在项目【Artisan.IotEdge.Application.Contracts】中添加如下服务接口,
代码清单:Artisan.IotEdge.Application.Contracts/Products/IProductServicepublic interface IProductService { Task
re>GetAsync(Guid productId); } 添加DTO:
public class ProductDto : AuditedEntityDto
re>{ public string Name { get; set; } } 添加AutoMapper
代码清单:Artisan.IotEdge.Application.Contracts/IotEdgeApplicationAutoMapperProfilepublic class IotEdgeApplicationAutoMapperProfile : Profile { public IotEdgeApplicationAutoMapperProfile() { CreateMap
re>(); } } 服务实现
在项目【Artisan.IotEdge.Application.Contracts】中添加如下服务实现,
代码清单:Artisan.IotEdge.Application/Products/ProductService
public class ProductService : ApplicationService, IProductService { private readonly ILogger
re>_logger; private readonly IObjectMapper _mapper; private readonly ProductPublic.ProductPublicClient _productPublicGrpcClient; public ProductService( ILogger logger, IObjectMapper mapper, ProductPublic.ProductPublicClient productPublicGrpcClient) { _logger = logger; _mapper = mapper; _productPublicGrpcClient = productPublicGrpcClient; } public async Task GetAsync(Guid productId) { var request = new ProductRequest { Id = productId.ToString() }; _logger.LogInformation("=== GRPC request {@request}", request); var response = await _productPublicGrpcClient.GetByIdAsync(request); _logger.LogInformation("=== GRPC response {@response}", response); return _mapper.Map (response) ?? throw new UserFriendlyException(IotEdgeDomainErrorCodes.ProductNotFound); } } 其中:
var response = await _productPublicGrpcClient.GetByIdAsync(request);
re>就是调用微服务:IotHub 的 gRpc 的服务
ApsNet Core 集成 gRpc
引用包
在项目【Artisan.IotEdge.HttpApi.Host】中引用如下包:
re>
添加 gRpc 客户端
代码清单:Artisan.IotEdge.HttpApi.Host/IotEdgeHttpApiHostModule.cs
public class IotEdgeHttpApiHostModule : AbpModule { public override void ConfigureServices(ServiceConfigurationContext context) { // ...... ConfigureGrpc(context, configuration); } private void ConfigureGrpc(ServiceConfigurationContext context, IConfiguration configuration) { context.Services.AddGrpcClient
re>((services, options) => { var iothubGrpcUrl = configuration["RemoteServices:IotHub:GrpcUrl"]; options.Address = new Uri(iothubGrpcUrl); }); } } 在配置文件
appsettings.json
中添加微服务IotHub的配置:"RemoteServices": { "IotHub": { "BaseUrl": "https://localhost:44359", "GrpcUrl": "http://localhost:81" } },
re>测试
启动微服务:IotHub
启动微服务:IotEdge
在微服务IotEdge的Swagger 中调用微服务IotHub的
PublicProductGrpcService
的GetById()
方法:微服务IotEdge 调用 微服务IotHub 的示意图如下所示:
返回结果:
{ "name": "TestProduct", "lastModificationTime": null, "lastModifierId": null, "creationTime": "0001-01-01T00:00:00", "creatorId": null, "id": "9af7f46a-ea52-4aa3-b8c3-9fd484c2af12" }
re>