• Abp vnext 微服务架构下集成 gRpc


    资料:

    https://docs.microsoft.com/zh-cn/aspnet/core/tutorials/grpc/grpc-start?view=aspnetcore-6.0&tabs=visual-studio

    Abp vNext 集成 gRpc

    为了演示,这里将创建两个微服务:

    1. Artisan.IotHub
    2. 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 # 解决方案
    │   │   └── ...
    └── ...
    

    微服务IotEdge 调用 微服务IotHub 的示意图如下所示:

    gRpc 服务端 : 微服务 IotHub

    创建微服务

    创建微服务 IotHub

    abp new Artisan.IotHub -u none -d ef -dbms SqlServer --separate-identity-server --version 5.2.1
    

    引用 gRpc 包

    项目【Artisan.IotHub.Application】引用 gRpc 服务端需要的包

      <ItemGroup>
        <PackageReference Include="Google.Protobuf" Version="3.20.1" />
        <PackageReference Include="Grpc.Core" Version="2.46.1" />
        <PackageReference Include="Grpc.Tools" Version="2.46.1">
       <ItemGroup>
    

    添加 *.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;
    }
    
    

    修改项目文件

    右键项目【Artisan.IotHub.Application】的工程文件,在弹出的菜单中选择【编译项目文件】,添加如下内容:

      <ItemGroup>
        <Protobuf Include="Protos\product.proto" GrpcServices="Server"/>
        <Content Include="@(Protobuf)" />
        <None Remove="@(Protobuf)" />
      </ItemGroup>
    

    其中,

    1. 节点:

      <Protobuf Include="Protos\product.proto" GrpcServices="Server"/>
      

      是设置 gRpc 的服务文件,以便 grpc.tools 该文件自动生成服务端代码

    2. 节点:

          <Content Include="@(Protobuf)" />
          <None Remove="@(Protobuf)" />
      

      *.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<ProductResponse> 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】引入如下包:

        <PackageReference Include="Grpc.AspNetCore.Server" Version="2.46.0" />
    

    添加服务

    代码清单:代码清单:Artisan.IotHub.HttpApi.Host/IotHubHttpApiHostModule.cs

    public class IotHubHttpApiHostModule : AbpModule
    {
        public override void ConfigureServices(ServiceConfigurationContext context)
        {
            //......
            ConfigureGrpc(context, configuration);
        }
        
        /// <summary>
        /// 将 gRPC 服务添加到 ASP.NET Core 应用
        /// https://docs.microsoft.com/zh-cn/aspnet/core/grpc/aspnetcore?view=aspnetcore-6.0&tabs=visual-studio
        /// </summary>
        /// <param name="context"></param>
        /// <param name="configuration"></param>
        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<PublicProductGrpcService>();
            });
        }
    }
    

    设置 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
          }
        }
      },
      // ......
    }
    

    特别注意:

    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
    

    引用包

    项目【Artisan.IotEdge.Application】引入如下包:

        <PackageReference Include="Google.Protobuf" Version="3.20.1" />
        <PackageReference Include="Grpc.Core" Version="2.46.1" />
        <PackageReference Include="Grpc.Tools" Version="2.46.1">
    

    *.proto 文件

    拷贝式

    可以将项目【 Artisan.IotHub.Application】下的 Artisan.IotHub.Application/Protos/product.proto 文件拷贝到项目【Artisan.IotEdge.Application】中,然后在项目【Artisan.IotEdge.Application】文件中添加:

      <ItemGroup>
        <Protobuf Include="Protos\product.proto" GrpcServices="Client"/>
      </ItemGroup>
    

    注意:GrpcServices="Client" 是 Client,而不是:Server

    但是这样做有点麻烦,当项目【 Artisan.IotHub.Application】的 Artisan.IotHub.Application/Protos/product.proto 文件修改了,还得拷贝一次,比较麻烦而且容易因为遗忘而出错。比较稳妥的做法是直接引用,而不是拷贝。

    引用式

    通过引用的方式,添加 *.proto 文件

    在项目【Artisan.IotEdge.Application】文件中添加:

      <ItemGroup>
        <Protobuf Include="..\..\..\iot-hub\src\Artisan.IotHub.Application\Protos\product.proto" GrpcServices="Client" />
      </ItemGroup>
    

    这样就不用拷贝项目【 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 # 解决方案
    │   │   └── ...
    └── ...
    

    编写调用 gRpc 服务

    服务接口

    在项目【Artisan.IotEdge.Application.Contracts】中添加如下服务接口,
    代码清单:Artisan.IotEdge.Application.Contracts/Products/IProductService

        public interface IProductService
        {
            Task<ProductDto> GetAsync(Guid productId);
        }
    

    添加DTO:

        public class ProductDto : AuditedEntityDto<Guid>
        {
            public string Name { get; set; }
        }
    

    添加AutoMapper
    代码清单:Artisan.IotEdge.Application.Contracts/IotEdgeApplicationAutoMapperProfile

    public class IotEdgeApplicationAutoMapperProfile : Profile
    {
        public IotEdgeApplicationAutoMapperProfile()
        {
            CreateMap<ProductResponse, ProductDto>();
        }
    }
    

    服务实现

    在项目【Artisan.IotEdge.Application.Contracts】中添加如下服务实现,

    代码清单:Artisan.IotEdge.Application/Products/ProductService

        public class ProductService : ApplicationService, IProductService
        {
            private readonly ILogger<ProductService> _logger;
            private readonly IObjectMapper _mapper;
            private readonly ProductPublic.ProductPublicClient _productPublicGrpcClient;
    
            public ProductService(
                ILogger<ProductService> logger,
                IObjectMapper mapper,
                 ProductPublic.ProductPublicClient productPublicGrpcClient)
            {
                _logger = logger;
                _mapper = mapper;
                _productPublicGrpcClient = productPublicGrpcClient;
            }
    
            public async Task<ProductDto> 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<ProductResponse, ProductDto>(response) ??
                       throw new UserFriendlyException(IotEdgeDomainErrorCodes.ProductNotFound);
            }
        }
    

    其中:

      var response = await _productPublicGrpcClient.GetByIdAsync(request);
    

    就是调用微服务:IotHub 的 gRpc 的服务

    ApsNet Core 集成 gRpc

    引用包

    在项目【Artisan.IotEdge.HttpApi.Host】中引用如下包:

        <PackageReference Include="Grpc.Net.ClientFactory" Version="2.46.0" />
    

    添加 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<ProductPublic.ProductPublicClient>((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"
        }
      },
    

    测试

    启动微服务:IotHub

    启动微服务:IotEdge

    在微服务IotEdge的Swagger 中调用微服务IotHub的 PublicProductGrpcServiceGetById()方法:

    微服务IotEdge 调用 微服务IotHub 的示意图如下所示:

    返回结果:

    {
      "name": "TestProduct",
      "lastModificationTime": null,
      "lastModifierId": null,
      "creationTime": "0001-01-01T00:00:00",
      "creatorId": null,
      "id": "9af7f46a-ea52-4aa3-b8c3-9fd484c2af12"
    }
    
  • 相关阅读:
    Vue 入门. 如何在HTML代码里面快速使用Vue
    CSS3 神器总结
    《JavaScript高级程序设计(第3版)》阅读总结记录第二章之在HTML中使用JavaScript
    《JavaScript高级程序设计(第3版)》阅读总结记录第一章之JavaScript简介
    简单轮播的实现
    怎么作好一个领导者?什么是团队?怎么当好一个组员?
    谈BFC和haslayout
    JavaScript 数组
    ubuntu配置android开发环境和编译源码遇到的一些问题
    C语言文件操作函数大全
  • 原文地址:https://www.cnblogs.com/easy5weikai/p/16288182.html
Copyright © 2020-2023  润新知