Dapr 运用
Dapr 运用
- 前置条件
- Docker
- Win10
Dapr 部署
本文将采用本地部署的方式。
安装 Dapr CLI
打开 Windows PowerShell 或 cmd ,运行以下命令以安装 Dapr CLI
,并添加安装路径到系统环境变量中。
powershell -Command "iwr -useb https://raw.githubusercontent.com/dapr/cli/master/install/install.ps1 | iex"
这里安装可能会失败。如果失败可以手动安装。
- 打开 Dapr 发布页面下载
dapr_windows_amd64.zip
- 解压文件 zip 文件
- 把解压后的文件拷贝到
C:\dapr
中
安装 MySql
Docker 启动 Mysql
docker run --name mysqltest -e MYSQL_ROOT_PASSWORD=123456 -d mysql
使用 Dapr CLI 安装 Darp runtime
在 Windows PowerShell 或 cmd 中使用命令 dapr init
以安装 Dapr。
同时可以在 Docker 中查看 Dapr 容器。
至此,一个本地 Dapr 服务搭建完成。
使用 Asp.Net Core
搭建 ProductService 服务
ProductService 提供两个服务
- 获取所有产品集合
- 添加产品
使用
ASP.Net Core
创建 ProductService ,具体参考源码Dapr 启动 ProductService
dapr run --app-id productService --app-port 5000 dotnet run
获取所有产品集合,使用 curl 命令
curl -X GET http://localhost:5000/getlist
或者
curl -X GET http://localhost:54680/v1.0/invoke/productService/method/getlist
添加一个产品
curl -X POST https://localhost:5001/product -H "Content-Type: application/json" -d "{ \"id\": \"14a3611d-1561-455f-9c72-381eed2f6ee3\" }"
重点,通过 Dapr 添加一个产品,先看添加产品的代码
/// <summary>
/// 创建产品
/// </summary>
/// <param name="productCreate">产品创建模型</param>
/// <returns></returns>
[Topic("product")]
[HttpPost("product")]
public async Task<bool> CreateProduct(ProductCreate productCreate)
{
_productContext.Products.Add(new Product
{
ProductID = productCreate.ID
});
return await _productContext.SaveChangesAsync() == 1;
}
使用 Dapr cli 发布事件
dapr invoke -a productService -m product -p "{\"id\":\"b1ccf14a-408a-428e-b0f0-06b97cbe4135\"}"
输出为:
true
App invoked successfully
使用 curl 命令直接请求 ProductService 地址
curl -X POST http://localhost:5000/product -H "Content-Type: application/json" -d "{ \"id\": \"14a3611d-1561-455f-9c72-381eed2f64e3\" }"
输出为:
true
使用 curl 命令通过 Dapr runtime
curl -X POST http://localhost:54680/v1.0/invoke/productService/method/product -H "Content-Type: application/json" -d "{ \"id\": \"14a3611d-1561-455f-9c72-381eed2f54e3\" }"
输出为:
true
注意:
- Dapr 使用 App 端口号应与服务端口号相同,例如:
ASP.Net Core
服务端口号为5000,则在使用 Dapr 托管应用程序时的端口号也应使用 5000
至此, ProductService 创建完成。
使用 Golang 创建 gRPC Server
创建 Server
package main import (
"context"
"fmt"
"log"
"net" "github.com/golang/protobuf/ptypes/any"
"github.com/golang/protobuf/ptypes/empty" pb "github.com/dapr/go-sdk/daprclient"
"google.golang.org/grpc"
) // server is our user app
type server struct {
} func main() {
// create listiner
lis, err := net.Listen("tcp", ":4000")
if err != nil {
log.Fatalf("failed to listen: %v", err)
} // create grpc server
s := grpc.NewServer()
pb.RegisterDaprClientServer(s, &server{}) fmt.Println("Client starting...") // and start...
if err := s.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
} // Sample method to invoke
func (s *server) MyMethod() string {
return "Hi there!"
} // This method gets invoked when a remote service has called the app through Dapr
// The payload carries a Method to identify the method, a set of metadata properties and an optional payload
func (s *server) OnInvoke(ctx context.Context, in *pb.InvokeEnvelope) (*any.Any, error) {
var response string fmt.Println(fmt.Sprintf("Got invoked with: %s", string(in.Data.Value))) switch in.Method {
case "MyMethod":
response = s.MyMethod()
}
return &any.Any{
Value: []byte(response),
}, nil
} // Dapr will call this method to get the list of topics the app wants to subscribe to. In this example, we are telling Dapr
// To subscribe to a topic named TopicA
func (s *server) GetTopicSubscriptions(ctx context.Context, in *empty.Empty) (*pb.GetTopicSubscriptionsEnvelope, error) {
return &pb.GetTopicSubscriptionsEnvelope{
Topics: []string{"TopicA"},
}, nil
} // Dapper will call this method to get the list of bindings the app will get invoked by. In this example, we are telling Dapr
// To invoke our app with a binding named storage
func (s *server) GetBindingsSubscriptions(ctx context.Context, in *empty.Empty) (*pb.GetBindingsSubscriptionsEnvelope, error) {
return &pb.GetBindingsSubscriptionsEnvelope{
Bindings: []string{"storage"},
}, nil
} // This method gets invoked every time a new event is fired from a registerd binding. The message carries the binding name, a payload and optional metadata
func (s *server) OnBindingEvent(ctx context.Context, in *pb.BindingEventEnvelope) (*pb.BindingResponseEnvelope, error) {
fmt.Println("Invoked from binding")
return &pb.BindingResponseEnvelope{}, nil
} // This method is fired whenever a message has been published to a topic that has been subscribed. Dapr sends published messages in a CloudEvents 0.3 envelope.
func (s *server) OnTopicEvent(ctx context.Context, in *pb.CloudEventEnvelope) (*empty.Empty, error) {
fmt.Println("Topic message arrived")
return &empty.Empty{}, nil
}使用 Dapr 命令启动 StorageService
dapr run --app-id client --protocol grpc --app-port 4000 go run main.go
注意:
- Dapr 使用 App 端口号应与服务端口号相同,使用 --protocal grpc 指定通讯协议为 grpc 。此外,OnInvoke 中的 switch 方法用于调用者路由。
使用 ASP.NET Core
创建 StorageService
使用 NuGet 获取程序管理包控制台安装以下包
- Dapr.AspNetCore
- Dapr.Client.Grpc
- Grpc.AspNetCore
- Grpc.Net.Client
- Grpc.Tools
Startup.cs
文件中修改代码如下:/// <summary>
/// This method gets called by the runtime. Use this method to add services to the container.
/// </summary>
/// <param name="services">Services.</param>
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers().AddDapr();
services.AddDbContextPool<StorageContext>(options => { options.UseMySql(Configuration.GetConnectionString("MysqlConnection")); });
}
/// <summary>
/// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
/// </summary>
/// <param name="app">app.</param>
/// <param name="env">env.</param>
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
} app.UseRouting();
app.UseCloudEvents(); app.UseAuthorization(); app.UseEndpoints(endpoints =>
{
endpoints.MapSubscribeHandler();
endpoints.MapControllers();
});
}
添加
StorageController.cs
文件,内容如下using System;
using System.Linq;
using System.Threading.Tasks;
using Dapr.Client.Grpc;
using Google.Protobuf;
using Grpc.Net.Client;
using Microsoft.AspNetCore.Mvc;
using StorageService.Api.Entities; namespace StorageService.Api.Controllers
{
[ApiController]
public class StorageController : ControllerBase
{
private readonly StorageContext _storageContext; public StorageController(StorageContext storageContext)
{
_storageContext = storageContext;
} /// <summary>
/// 初始化仓库.
/// </summary>
/// <returns>是否成功.</returns>
[HttpGet("InitialStorage")]
public async Task<bool> InitialStorage()
{
string defaultPort = Environment.GetEnvironmentVariable("DAPR_GRPC_PORT") ?? "54681"; // 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);
Console.WriteLine(daprUri); InvokeServiceResponseEnvelope result = await client.InvokeServiceAsync(new InvokeServiceEnvelope
{
Method = "MyMethod",
Id = "client",
Data = new Google.Protobuf.WellKnownTypes.Any
{
Value = ByteString.CopyFromUtf8("Hello ProductService")
}
});
Console.WriteLine("this is call result:" + result.Data.Value.ToStringUtf8());
//var productResult = result.Data.Unpack<ProductList.V1.ProductList>();
//Console.WriteLine("this is call result:" + productResult.Results.FirstOrDefault());
return true;
} /// <summary>
/// 修改库存
/// </summary>
/// <param name="storage"></param>
/// <returns></returns>
[HttpPut("Reduce")]
public bool Reduce(Storage storage)
{
Storage storageFromDb = _storageContext.Storage.FirstOrDefault(q => q.ProductID.Equals(storage.ProductID));
if (storageFromDb == null)
{
return false;
} if (storageFromDb.Amount <= storage.Amount)
{
return false;
} storageFromDb.Amount -= storage.Amount;
return true;
}
}
}
使用 Dapr cli 启用 StorageService 服务
dapr run --app-id storageService --app-port 5003 dotnet run
使用 curl 命令访问 StorageService InitialStorage 方法
curl -X GET http://localhost:56349/v1.0/invoke/storageService/method/InitialStorage
输入
true
其中打印信息为:
this is call result:Hi there!
注意:
- Dapr 使用 App 端口号应与服务端口号相同,例如:
ASP.Net Core
服务端口号为5003,则在使用 Dapr 托管应用程序时的端口号也应使用 5003,在 Client.InvokeServiceAsync 中的 Id 指被调用方的 App-Id ,Method 指被调用方方法名称。参考 Go Server 中 OnInvoke 方法的 Switch 。
Dapr 运用的更多相关文章
- 技术分享:Dapr,让开发人员更轻松地构建微服务应用
最近一直在学习微服务相关的技术.微服务架构已成为构建云原生应用程序的标准,并且可以预见,到2022年,将有90%的新应用程序采用微服务架构.微服务架构提供了令人信服的好处,包括可伸缩性,松散的服务耦合 ...
- 微软的分布式应用框架 Dapr Helloworld
Dapr HelloWorld Dapr Distributed Application Runtime. An event-driven, portable runtime for building ...
- 微软的分布式应用框架 Dapr
微服务架构已成为构建云原生应用程序的标准,微服务架构提供了令人信服的好处,包括可伸缩性,松散的服务耦合和独立部署,但是这种方法的成本很高,需要了解和熟练掌握分布式系统.为了使用所有开发人员能够使用任何 ...
- dapr微服务.netcore sdk入门
Actors入门 先决条件 .Net Core SDK 3.0 Dapr CLI Dapr DotNet SDK 概述 本文档描述如何在客户端应用程序上创建Actor(MyActor)并调用其方法. ...
- Dapr 运用之 Java gRPC 调用篇
JAVA GRPC 服务与调用 安装协议编译器 下载对应的版本编译器,并把路径加入到环境变量中,执行以下命令生成代码 protoc -I=$SRC_DIR --java_out=$DST_DIR $S ...
- Dapr 运用之集成 Asp.Net Core Grpc 调用篇
前置条件: <Dapr 运用> 改造 ProductService 以提供 gRPC 服务 从 NuGet 或程序包管理控制台安装 gRPC 服务必须的包 Grpc.AspNetCore ...
- .NetCore集成Dapr踩坑经历
该篇内容由个人博客点击跳转同步更新!转载请注明出处 前言 之前自己有个core2.2的项目一直是用的Surging作为微服务框架的,后来了解到了Dapr,发现比较轻量级,开发部署等也非常方便,故将自己 ...
- Dapr Pub/Sub 集成 RabbitMQ 、Golang、Java、DotNet Core
前置条件: <Dapr运用> <Dapr 运用之 Java gRPC 调用篇> <Dapr 运用之集成 Asp.Net Core Grpc 调用篇> 搭建 Rabb ...
- Dapr实现分布式有状态服务的细节
Dapr是为云上环境设计的跨语言, 事件驱动, 可以便捷的构建微服务的系统. balabala一堆, 有兴趣的小伙伴可以去了解一下. Dapr提供有状态和无状态的微服务. 大部分人都是做无状态服务(微 ...
随机推荐
- Linux下安装nexus
下载地址:https://help.sonatype.com/repomanager3/download tar xf nexus-linux-3.19.1-01.tar.gz cd nexus-li ...
- css3的过渡和动画的属性介绍
一.过渡 什么是过渡? 过渡是指:某元素的css属性值在一段时间内,平滑过渡到另外一个值,过渡主要观察的是过程和结果. 设置能够过渡的属性: 支持过渡的样式属性,颜色的属性,取值为数值,transfo ...
- 淘宝小练习#css
* { margin: 0; padding: 0; } a { text-decoration: none; } .box { background: #f4f4f4; } /* 头部样式STAR ...
- Kubernetes Horizontal Pod Autoscaling
HPA介绍 Horizontal Pod Autoscaler基于观察到的CPU利用率(或借助自定义指标 支持,基于其他一些应用程序提供的指标)自动缩放复制控制器,部署或副本集中的Pod数量 .请 ...
- ES6学习 let const
1.前言 发现网易云笔记 单纯的记笔记没什么意思,所以今天来博客园写学习感受了,毕设做了休息时间就来写写新学的知识 哈哈哈 !! 2.ES6 就是JavaScript 语言的下一代标准,2015年6月 ...
- 关于 Python 对象拷贝的那点事?
概述 在本篇文章中,会先介绍 Python 中对象的基础概念,之后会提到对象的深浅拷贝以及区别.在阅读后,应该掌握如下的内容: 理解变量.引用和对象的关系 理解 Python 对象中 identity ...
- vant-ui的van-uploader上传图片
移动端上传图片是很常用的功能,这里使用vant-ui实现. 效果如图 上传图片的vue页面:Customer.vue html <div :class="postData.length ...
- 更改input标签的placeholder的样式
主要是要区别不同浏览器的不同css类 在input框中有时想将输入的字和placeholder设为不同的颜色或其它效果,这时就可以用以下代码来对placeholder进行样式设置了. input::- ...
- 三种方法教你HTML实现点击某一个元素之外触发事件
HTML实现点击某一个元素之外触发事件 大致编写的HTML界面渲染后是这个样子的,我们现在想要实现的需求是点击Button所在的div不会触发事件,而在点击Button所在的div之外的区域时会触发事 ...
- 使用Publisher2016快速给图片添加水印
打开Publisher,根据图片大小及形状选择空白页面大小,此处选择纵向: 点击图标选择图片: 点击绘制文本框: 在文本框中编辑水印内容,对文字大小.字体.颜色进行调整,此处将水印颜色调整为灰色,拖动 ...