Dapr 运用之集成 Asp.Net Core Grpc 调用篇
前置条件: 《Dapr 运用》
改造 ProductService 以提供 gRPC 服务
从 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
01, listenOptions =>
{
listenOptions.Protocols = HttpProtocols.Http2;
});
});
webBuilder.UseStartup();
});
}
```
新建了 product.proto 以定义 GRPC 服务,它需要完成的内容是返回所有产品集合,当然目前产品内容只有一个 ID
定义产品 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;
}
说明
- 定义产品列表 gRPC 服务,得益于宇宙第一 IDE Visual Studio ,只要添加 Grpc.Tools 包就可以自动生成 gRPC 所需的代码,这里不再需要手动去添加 Grpc.Tools ,官方提供的 Grpc.AspNetCore 中已经集成了
- 定义了一个服务 ProductRPCService
- 定义了一个函数 ProductRPCService
- 定义了一个请求构造 ProductListRequest ,内容为空
- 定义了一个请求返回构造 ProductList ,使用 repeated 表明返回数据是集合
- 定义了一个数据集合中的一个对象 Product
添加 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;
}
说明
- 此文件为官方提供,Dapr 0.3 版本之前提供的已经生成好的代码,现在看源码可以看出已经改为提供 proto 文件了,这里我认为提供 proto 文件比较合理
- 此文件定义了5个函数,此文主要讲的就是
OnInvoke()
函数 OnInvoke()
请求构造为InvokeEnvelope
- method 提供调用方法名称
- data 请求数据
- metadata 额外数据,此处使用键值对形式体现
创建 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 服务调用
添加 productList.proto 文件,内容同 ProductService 中的 productList.proto
添加 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;
}
说明
- 此文件提供6个 GRPC 服务,此文介绍的函数为
InvokeService()
- 请求构造为 InvokeServiceEnvelope
- id 请求的服务的 --app-id ,比如 productService
- method 请求的方法
- data 请求函数的签名
- metadata 元数据键值对
- 请求构造为 InvokeServiceEnvelope
修改 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 Client
string 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 服务的调用。
Dapr 运用之集成 Asp.Net Core Grpc 调用篇的更多相关文章
- 旧 WCF 项目迁移到 asp.net core + gRPC 的尝试
一个月前,公司的运行WCF的windows服务器down掉了,由于 AWS 没有通知,没有能第一时间发现问题. 所以,客户提出将WCF服务由C#改为JAVA,在Linux上面运行:一方面,AWS对Li ...
- ASP.NET Core gRPC 入门全家桶
一. 说明 本全家桶现在只包含了入门级别的资料,实战资料更新中. 二.官方文档 gRPC in Asp.Net Core :官方文档 gRPC 官网:点我跳转 三.入门全家桶 正片: ASP.NET ...
- ASP.NET Core gRPC 健康检查的实现方式
一. 前言 gRPC 服务实现健康检查有两种方式,前面在此文 ASP.NET Core gRPC 使用 Consul 服务注册发现 中有提到过,这里归纳整理一下.gRPC 的健康检查,官方是定义了标准 ...
- 从零搭建一个IdentityServer——集成Asp.net core Identity
前面的文章使用Asp.net core 5.0以及IdentityServer4搭建了一个基础的验证服务器,并实现了基于客户端证书的Oauth2.0授权流程,以及通过access token访问被保护 ...
- ASP.NET Core GRPC 和 Dubbo 互通
一.前言 Dubbo 是比较流行的服务治理框架,国内不少大厂都在使用.以前的 Dubbo 使用的是私有协议,采集用的 hessian 序列化,对于多语言生态来说是极度的不友好.现在 Dubbo 发布了 ...
- .NET Core实战项目之CMS 第二章 入门篇-快速入门ASP.NET Core看这篇就够了
作者:依乐祝 原文链接:https://www.cnblogs.com/yilezhu/p/9985451.html 本来这篇只是想简单介绍下ASP.NET Core MVC项目的(毕竟要照顾到很多新 ...
- net core体系-web应用程序-4asp.net core2.0 项目实战(CMS)-第二章 入门篇-快速入门ASP.NET Core看这篇就够了
.NET Core实战项目之CMS 第二章 入门篇-快速入门ASP.NET Core看这篇就够了 原文链接:https://www.cnblogs.com/yilezhu/p/9985451.ht ...
- ASP.NET Core gRPC 使用 Consul 服务注册发现
一. 前言 gRPC 在当前最常见的应用就是在微服务场景中,所以不可避免的会有服务注册与发现问题,我们使用gRPC实现的服务可以使用 Consul 或者 etcd 作为服务注册与发现中心,本文主要介绍 ...
- 5. abp集成asp.net core
一.前言 参照前篇<4. abp中的asp.net core模块剖析>,首先放张图,这也是asp.net core框架上MVC模块的扩展点 二.abp的mvc对象 AbpAspNetCor ...
随机推荐
- 领扣(LeetCode)二叉树的右视图 个人题解
给定一棵二叉树,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值. 示例: 输入: [1,2,3,null,5,null,4] 输出: [1, 3, 4] 解释: 1 < ...
- 扛把子 选题 Scrum立会报告+燃尽图 03
此作业要求参见:https://edu.cnblogs.com/campus/nenu/2019fall/homework/8680 一.小组情况组长:迟俊文组员:宋晓丽 梁梦瑶 韩昊 刘信鹏队名:扛 ...
- 数据类型-Java基础一-初学者笔记
初学者笔记 1.Java中的两种类型 在java源代码中,每个变量都必须声明一种类型(type). 有两种类型:primitive type和reference type.引用类型引用对象(ref ...
- 使用RNN进行imdb影评情感识别--use RNN to sentiment analysis
原创帖子,转载请说明出处 一.RNN神经网络结构 RNN隐藏层神经元的连接方式和普通神经网路的连接方式有一个非常明显的区别,就是同一层的神经元的输出也成为了这一层神经元的输入.当然同一时刻的输出是不可 ...
- ssm通用 POM
<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven ...
- python面试题(实时更新)
1.以下代码输出为: list1 = {':2} list2 = list1 list1['] = 5 sum = list1['] print(sum) 解析:10 b = a: 赋值引用,a 和 ...
- scrapy框架安装配置
scrapy框架 scrapy安装(win) 1.pip insatll wheel 2.下载合适的版本的twisted:http://www.lfd.uci.edu/~gohlke/pythonli ...
- PAT甲级专题|最短路
PAT甲级最短路 主要算法:dijkstra 求最短最长路.dfs图论搜索. 1018,dijkstra记录路径 + dfs搜索路径最值 25分,错误点暂时找不出.. 如果只用dijkstra没法做, ...
- 基于JDK1.8的JVM 内存结构【JVM篇三】
目录 1.内存结构还是运行时数据区? 2.运行时数据区 3.线程共享:Java堆.方法区 4.线程私有:程序计数器.Java 虚拟机栈.本地方法栈 5.JVM 内存结构总结 在我的上一篇文章别翻了,这 ...
- 华为OSPF与ACL综合应用实例讲解
OSPF与ACL综合应用实例讲解 项目案例要求: 1.企业内网运行OSPF路由协议,区域规划如图所示:2.财务和研发所在的区域不受其他区域链路不稳定性影响:3.R1.R2.R3只允许被IT登录管理:4 ...