Dapr 运用之集成 Asp.Net Core Grpc 调用篇

前置条件: 《Dapr 运用》


改造 ProductService 以提供 gRPC 服务

  1. 从 NuGet 或程序包管理控制台安装 gRPC 服务必须的包

  • Grpc.AspNetCore

  • 配置 Http/2

    • gRPC 服务需要 Http/2 协议

      public static IHostBuilder CreateHostBuilder(string[] args)
      {return Host.CreateDefaultBuilder(args).ConfigureWebHostDefaults(webBuilder =>{webBuilder.ConfigureKestrel(options =>{options.Listen(IPAddress.Loopback, 50![](https://img2018.cnblogs.com/blog/757544/201912/757544-20191218205830077-211023565.png)
      01, listenOptions =>{listenOptions.Protocols = HttpProtocols.Http2;});});webBuilder.UseStartup<Startup>();});
      }
  • 新建了 product.proto 以定义 GRPC 服务,它需要完成的内容是返回所有产品集合,当然目前产品内容只有一个 ID

    • 定义产品列表 gRPC 服务,得益于宇宙第一 IDE Visual Studio ,只要添加 Grpc.Tools 包就可以自动生成 gRPC 所需的代码,这里不再需要手动去添加 Grpc.Tools ,官方提供的 Grpc.AspNetCore 中已经集成了

    • 定义了一个服务 ProductRPCService

    • 定义了一个函数 ProductRPCService

    • 定义了一个请求构造 ProductListRequest ,内容为空

    • 定义了一个请求返回构造 ProductList ,使用 repeated 表明返回数据是集合

    • 定义了一个数据集合中的一个对象 Product

    • 定义产品 proto

      syntax = "proto3";package productlist.v1;option csharp_namespace = "ProductList.V1";service ProductRPCService{rpc GetAllProducts(ProductListRequest) returns(ProductList);
      }message ProductListRequest{}message ProductList {repeated Product results = 1;
      }message Product {string ID=1;
      }

      说明

    • 添加 ProductListService 文件,内容如下

          public class ProductListService : ProductRPCService.ProductRPCServiceBase{private readonly ProductContext _productContext;public ProductListService(ProductContext productContext){_productContext = productContext;}public override async Task<ProductList.V1.ProductList> GetAllProducts(ProductListRequest request, ServerCallContext context){IList<Product> results = await _productContext.Products.ToListAsync();var productList = new ProductList.V1.ProductList();foreach (Product item in results){productList.Results.Add(new ProductList.V1.Product{ID = item.ProductID.ToString()});}return productList;}}
  • 在 Startup.cs 修改代码如下

    public void ConfigureServices(IServiceCollection services)
    {//启用 gRPC 服务services.AddGrpc();services.AddTransient<ProductListService>();...
    }

    这里的 services.AddTransient(); 的原因是在 Dapr 中需要使用构造器注入,以完成 GetAllProducts(...) 函数的调用

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {if (env.IsDevelopment()){app.UseDeveloperExceptionPage();}app.UseRouting();app.UseEndpoints(endpoints =>{...//添加 gRPC 到路由管道中endpoints.MapGrpcService<DaprClientService>();});
    }

    这里添加的代码的含义分别是启用 gRPC 服务和添加 gRPC 路由。得益于 ASP.NET Core 中间件的优秀设计,ASP.NET Core 可同时支持 Http 服务。

  • 添加 daprclient.proto 文件以生成 Dapr Grpc 服务,daprclient.proto 内容如下

    syntax = "proto3";package daprclient;import "google/protobuf/any.proto";
    import "google/protobuf/empty.proto";
    import "google/protobuf/duration.proto";option java_outer_classname = "DaprClientProtos";
    option java_package = "io.dapr";// User Code definitions
    service DaprClient {
    rpc OnInvoke (InvokeEnvelope) returns (google.protobuf.Any) {}
    rpc GetTopicSubscriptions(google.protobuf.Empty) returns (GetTopicSubscriptionsEnvelope) {}
    rpc GetBindingsSubscriptions(google.protobuf.Empty) returns (GetBindingsSubscriptionsEnvelope) {}
    rpc OnBindingEvent(BindingEventEnvelope) returns (BindingResponseEnvelope) {}
    rpc OnTopicEvent(CloudEventEnvelope) returns (google.protobuf.Empty) {}
    }message CloudEventEnvelope {
    string id = 1;
    string source = 2;
    string type = 3;
    string specVersion = 4;
    string dataContentType = 5;
    string topic = 6;
    google.protobuf.Any data = 7;
    }message BindingEventEnvelope {string name = 1;google.protobuf.Any data = 2;map<string,string> metadata = 3;
    }message BindingResponseEnvelope {
    google.protobuf.Any data = 1;
    repeated string to = 2;
    repeated State state = 3;
    string concurrency = 4;
    }message InvokeEnvelope {string method = 1;google.protobuf.Any data = 2;map<string,string> metadata = 3;
    }message GetTopicSubscriptionsEnvelope {
    repeated string topics = 1;
    }message GetBindingsSubscriptionsEnvelope {
    repeated string bindings = 1;
    }message State {
    string key = 1;
    google.protobuf.Any value = 2;
    string etag = 3;
    map<string,string> metadata = 4;
    StateOptions options = 5;
    }message StateOptions {
    string concurrency = 1;
    string consistency = 2;
    RetryPolicy retryPolicy = 3;
    }message RetryPolicy {
    int32 threshold = 1;
    string pattern = 2;
    google.protobuf.Duration interval = 3;
    }

    说明

    • method 提供调用方法名称

    • data 请求数据

    • metadata 额外数据,此处使用键值对形式体现

    • 此文件为官方提供,Dapr 0.3 版本之前提供的已经生成好的代码,现在看源码可以看出已经改为提供 proto 文件了,这里我认为提供 proto 文件比较合理

    • 此文件定义了5个函数,此文主要讲的就是 OnInvoke() 函数

    • OnInvoke() 请求构造为 InvokeEnvelope

  • 创建 DaprClientService.cs 文件,此文件用于终结点路由,内容为

    public class DaprClientService : DaprClient.DaprClientBase
    {private readonly ProductListService _productListService;/// <summary>/// Initializes a new instance of the <see cref="ProductService" /> class./// </summary>/// <param name="productListService"></param>public DaprClientService(ProductListService productListService){_productListService = productListService;}public override async Task<Any> OnInvoke(InvokeEnvelope request, ServerCallContext context){switch (request.Method){case "GetAllProducts":ProductListRequest productListRequest = ProductListRequest.Parser.ParseFrom(request.Data.Value);ProductList.V1.ProductList productsList = await _productListService.GetAllProducts(productListRequest, context);return Any.Pack(productsList);}return null;}
    }

    说明

    • 使用构造器注入已定义好的 ProductListService

    • InvokeEnvelope 中的 Method 用于路由数据

    • 使用 ProductListRequest.Parser.ParseFrom 转换请求构造

    • 使用 Any.Pack() 打包需要返回的数据

  • 运行 productService

    dapr run --app-id productService --app-port 5001 --protocol grpc dotnet run
  • 小结
    至此,ProductService 服务完成。此时 ProductService.Api.csproj Protobuf 内容为

    <ItemGroup><Protobuf Include="Protos\daprclient.proto" GrpcServices="Server" /><Protobuf Include="Protos\productList.proto" GrpcServices="Server" /></ItemGroup>

    改造 StorageService 服务以完成 Dapr GRPC 服务调用

    1. 添加 productList.proto 文件,内容同 ProductService 中的 productList.proto

    2. 添加 dapr.proto 文件,此文件也为官方提供,内容为

      syntax = "proto3";package dapr;import "google/protobuf/any.proto";
      import "google/protobuf/empty.proto";
      import "google/protobuf/duration.proto";option java_outer_classname = "DaprProtos";
      option java_package = "io.dapr";option csharp_namespace = "Dapr.Client.Grpc";// Dapr definitions
      service Dapr {
      rpc PublishEvent(PublishEventEnvelope) returns (google.protobuf.Empty) {}
      rpc InvokeService(InvokeServiceEnvelope) returns (InvokeServiceResponseEnvelope) {}
      rpc InvokeBinding(InvokeBindingEnvelope) returns (google.protobuf.Empty) {}
      rpc GetState(GetStateEnvelope) returns (GetStateResponseEnvelope) {}
      rpc SaveState(SaveStateEnvelope) returns (google.protobuf.Empty) {}
      rpc DeleteState(DeleteStateEnvelope) returns (google.protobuf.Empty) {}
      }message InvokeServiceResponseEnvelope {
      google.protobuf.Any data = 1;
      map<string,string> metadata = 2;
      }message DeleteStateEnvelope {
      string key = 1;
      string etag = 2;
      StateOptions options = 3;
      }message SaveStateEnvelope {
      repeated StateRequest requests = 1;
      }message GetStateEnvelope {string key = 1;string consistency = 2;
      }message GetStateResponseEnvelope {
      google.protobuf.Any data = 1;
      string etag = 2;
      }message InvokeBindingEnvelope {
      string name = 1;
      google.protobuf.Any data = 2;
      map<string,string> metadata = 3;
      }message InvokeServiceEnvelope {
      string id = 1;
      string method = 2;
      google.protobuf.Any data = 3;
      map<string,string> metadata = 4;
      }message PublishEventEnvelope {string topic = 1;google.protobuf.Any data = 2;
      }message State {
      string key = 1;
      google.protobuf.Any value = 2;
      string etag = 3;
      map<string,string> metadata = 4;
      StateOptions options = 5;
      }message StateOptions {
      string concurrency = 1;
      string consistency = 2;
      RetryPolicy retryPolicy = 3;
      }message RetryPolicy {
      int32 threshold = 1;
      string pattern = 2;
      google.protobuf.Duration interval = 3;
      }message StateRequest {
      string key = 1;
      google.protobuf.Any value = 2;
      string etag = 3;
      map<string,string> metadata = 4;
      StateRequestOptions options = 5;
      }message StateRequestOptions {
      string concurrency = 1;
      string consistency = 2;
      StateRetryPolicy retryPolicy = 3;
      }message StateRetryPolicy {
      int32 threshold = 1;
      string pattern = 2;
      google.protobuf.Duration interval = 3;
      }

      说明

    • 请求构造为 InvokeServiceEnvelope

    • id 请求的服务的 --app-id ,比如 productService

    • method 请求的方法

    • data 请求函数的签名

    • metadata 元数据键值对

    • 此文件提供6个 GRPC 服务,此文介绍的函数为 InvokeService()

  • 修改 StorageController 中的 InitialStorage() 函数为

    /// <summary>
    /// 初始化仓库.
    /// </summary>
    /// <returns>是否成功.</returns>
    [HttpGet("InitialStorage")]
    public async Task<bool> InitialStorage()
    {string defaultPort = Environment.GetEnvironmentVariable("DAPR_GRPC_PORT") ?? "5001";// Set correct switch to make insecure gRPC service calls. This switch must be set before creating the GrpcChannel.AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);// Create Clientstring daprUri = $"http://127.0.0.1:{defaultPort}";GrpcChannel channel = GrpcChannel.ForAddress(daprUri);var client = new Dapr.Client.Grpc.Dapr.DaprClient(channel);InvokeServiceResponseEnvelope result = await client.InvokeServiceAsync(new InvokeServiceEnvelope{Method = "GetAllProducts",Id = "productService",Data = Any.Pack(new ProductListRequest())});ProductList.V1.ProductList productResult = ProductList.V1.ProductList.Parser.ParseFrom(result.Data.Value);var random = new Random();foreach (Product item in productResult.Results){_storageContext.Storage.Add(new Storage{ProductID = Guid.Parse(item.ID),Amount = random.Next(1, 1000)});}await _storageContext.SaveChangesAsync();return true;
    }
  • 启动 StorageService

    dapr run --app-id storageService --app-port 5003 dotnet run
  • 使用 Postman 请求 StorageService 的 InitialStorage

  • 使用 MySql Workbench 查看结果

  • 小结
    至此,以 Dapr 框架使用 GRPC 客户端在 StorageService 中完成了对 ProductService 服务的调用。

    源码地址: https://github.com/SoMeDay-Zhang/DaprDemos/tree/master/dotnetcore 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/312624.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

蓝桥杯 印章拿金币

今日心得 对于大数组的定义要放在main函数外&#xff0c;否则会报错认真思考动态规划的边界设置&#xff0c;不是机械地设置1或0 动态转移方程&#xff1a; dp[i][j] dp[i-1][j]*j/n dp[i-1][j-1]*(n-j1)/n;参考代码 #include<bits/stdc.h> using namespace std;int…

ASP.NET Core Web API 最佳实践指南

原文地址&#xff1a; ASP.NET-Core-Web-API-Best-Practices-Guide介绍当我们编写一个项目的时候&#xff0c;我们的主要目标是使它能如期运行&#xff0c;并尽可能地满足所有用户需求。但是&#xff0c;你难道不认为创建一个能正常工作的项目还不够吗&#xff1f;同时这个项目…

蓝桥杯 砝码称重

试题&#xff1a; 思路&#xff1a; 经典的0-1背包问题&#xff0c;这题坑的地方在于方案数会超过边界&#xff0c;当发现当前重量可行时&#xff0c;直接归为1&#xff0c;防止dp数组累加时溢出。或者最后统计的时候&#xff0c;将判断条件从if(dp[n][i])>0改为if(dp[n][i…

[小技巧]你真的了解C#中的Math.Round么?

今天在某.NET Core 群中看到有人在问Math.Round的问题。其实这个问题之前有很多人遇到了&#xff0c;在此总结一下。开发者为了实现小数点后 2 位的四舍五入&#xff0c;编写了如下代码&#xff0c;var num Math.Round(12.125, 2);代码非常的简单&#xff0c;开发者实际得到的…

蓝桥杯 左baby右兄弟

试题&#xff1a; 思路&#xff1a; “左孩子右兄弟”是常见的多叉树转化成二叉树的方法。具体的实现方式是&#xff0c;从第二层最右边的结点开始&#xff0c;将将自己的孩子结点放到左边&#xff0c;左边一位的兄弟放到左边的结点上。对于是多支的孩子先递归转成一支树。 本…

一文带你了解如何打造持续学习文化

一个学习型组织&#xff0c;必须是通过致力于不懈地改进和促进创新的文化来实现的。持续学习文化能力描述了一套鼓励个人和整个企业不断增长知识、能力、绩效和创新的价值观和实践。它是精益企业的七个核心能力之一&#xff0c;每一个都是实现业务敏捷的关键点。为什么要持续学…

蓝桥杯 数字三角形 贪心+动态规划

参考代码&#xff1a; #include<bits/stdc.h> using namespace std; typedef long long ll; int data[105][105];int main() {ios::sync_with_stdio(false);int n;cin >> n;for(int i 1; i < n; i){for(int j 1; j < i; j){cin >> data[i][j];}}int…

【.NET Core 跨平台 GUI 开发】第三篇:Gtk# 表格布局与事件处理

除了使用 HBox 和 VBox 进行布局外&#xff0c;还可以使用 Table 对象进行布局。这个有点像 html 的 table&#xff0c;适合方方正正大小差不多的空间集合。本篇将会对 Table 布局进行讲解&#xff0c;利用 Table 做出一个计算器的界面并使其可以响应按钮点击并将点击的按钮内容…

如何构建知识体系

大家好&#xff0c;我是Z哥。不知道你有没有过这样的感觉&#xff0c;那些比你更厉害的人&#xff0c;在一件事中往往可以轻易地从一个「点」延展出一条「线」&#xff0c;甚至一个「面」的知识点。对我们真实感受的冲击是&#xff0c;在大局观上被碾压&#xff0c;相比之下觉得…

蓝桥杯 递增序列

思路&#xff1a; 这道题一开始想复杂了&#xff0c;其实这么小的数据量直接暴力求解即可。 参考代码&#xff1a; #include<bits/stdc.h> using namespace std; typedef long long ll; int m 30, n 50;bool checkL(int x, int y) //判断坐标是否超出边界 {if(x &g…

使用DbContextPool提高EfCore查询性能

长话短说上个月公司上线了一个物联网数据科学项目&#xff0c;我主要负责前端接收设备Event&#xff0c;并提供模型参数下载&#xff08;数据科学团队会优化参数&#xff09;。WebApp部署在Azure&#xff0c;模型参数使用Azure SQL Server存储。最近从灰度测试转向全量部署之后…

蓝桥杯 分巧克力 二分

#include<bits/stdc.h> using namespace std; typedef long long ll; ll n, k; vector<ll> width, height;bool check(ll length) //判断边长为length的正方形都否满足需求 {ll sum 0; //记录能切成的最大方块数 for(int i 0; i < n; i){sum (width[i] / …

[原]调试实战——程序CPU占用率飙升,你知道如何快速定位吗?

前言 如果我们自己的程序的CPU Usage&#xff08;CPU占用率&#xff09;飙升&#xff0c;并且居高不下&#xff0c;很有可能陷入了死循环。你知道怎么快速定位并解决吗&#xff1f;今天跟大家分享几种定位方法&#xff0c;希望对你有所帮助。如何判断是否有死循环&#xff1f; …

蓝桥杯 迷宫

参考代码&#xff1a; #include<bits/stdc.h> using namespace std; typedef long long ll; int e[55][55], vis[55][55]; //e矩阵表示障碍物信息&#xff0c;vis矩阵表示点是否被访问过 int m 30, n 50; struct node{ //定义结构体&#xff0c;用于存放点的信息 i…

ASP.NET Core基于K8S的微服务电商案例实践--学习笔记

摘要一个完整的电商项目微服务的实践过程&#xff0c;从选型、业务设计、架构设计到开发过程管理、以及上线运维的完整过程总结与剖析。讲师介绍产品需求介绍纯线上商城线上线下一体化跨行业跨商业模式从0开始&#xff0c;我们应该采用微服务吗&#xff1f;不适合采用微服务架构…

蓝桥杯 日志统计 尺取

参考代码&#xff1a; #include<bits/stdc.h> using namespace std; typedef long long ll; vector<int> v[100005]; //定义容器用于存放第i篇帖子被点赞的时间 int main() {ios::sync_with_stdio(false); int n, d, k;cin >> n >> d >> k;in…

2019 ASP.NET Core 之微调查报告,新鲜出炉

▼更多精彩推荐&#xff0c;上午11点到达▼在本周三的时候&#xff0c;因为直播没有找到合适内容的缘故&#xff0c;因此在我的公众号内发起了一波问卷调查&#xff0c;地址是&#xff1a;【壹个问卷】NetCore学习的知识点调查&#xff0c;当时就是想着有十来份儿就已经很给面子…

蓝桥杯 子串分值

参考代码&#xff1a; #include<bits/stdc.h> using namespace std;int main() {ios::sync_with_stdio(false); string str;cin >> str;int sum 0;int left, right;char s;int len str.size();for(int i 0; i < len; i) //依次循环每一个字符&#xff0c;…

基于 Blazui 的 Blazor 后台管理模板 BlazAdmin 正式尝鲜

简介BlazAdmin 是一个基于Blazui的后台管理模板&#xff0c;无JS&#xff0c;无TS&#xff0c;非 Silverlight&#xff0c;非 WebForm&#xff0c;一个标签即可使用。  我将在下一篇文章讨论 Blazor 服务器端渲染与客户端渲染的基本原理&#xff0c;对比服务器端渲染与 WebFo…

蓝桥杯 123 二分+打表

参考代码&#xff1a; #include<bits/stdc.h> using namespace std; typedef long long ll; ll temp[1500000], sum[1500000]; //temp数组记录序号和&#xff0c;sum数组记录前缀和 ll cal(ll n) //计算自然数求和 {return (n1)*n/2; }int main() {ios::sync_with_s…