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提供有状态和无状态的微服务. 大部分人都是做无状态服务(微 ...
随机推荐
- Git连接GitHub仓库详解
[Annotation]本文将从标题八开始,因为前七个标题是关于Git的基本操作,如果对Git的基本操作不了解的话,可以点击下方链接先看一下Git怎么使用. 关于Git的详细使用 八:创建SSH Ke ...
- 【转载】常见十大经典排序算法及C语言实现【附动图图解】
原文链接:https://www.cnblogs.com/onepixel/p/7674659.html 注意: 原文中的算法实现都是基于JS,本文全部修改为C实现,并且统一排序接口,另外增加了一些描 ...
- linux中jdk的安装
//先检查jdk有没有安装 java -version cp jdk-7u79-linux-x64.tar.gz /usr/local/ cd /usr/local/ tar -zxvf jdk- ...
- 理解clientWidth,offsetWidth,clientLeft,offsetLeft,clientX,offsetX,pageX,screenX
1. clientWidth:表示元素的内部宽度,以像素计.该属性包括内边距,但不包括垂直滚动条(如果有).边框和外边距.(clientWidth = width + padding) 2. offs ...
- PHP 面试踩过的坑
1.get,post 的区别 **显示有区别 ** get方法是将字符串拼接在地址栏后面可以看见 而post方法看不见 **传递的大小有区别 ** 具体大小和浏览器有关系,ie浏览器是2k其他浏览器的 ...
- WordPress 添加title中的logo
WordPress 添加title中的logo <!--网页标题左侧显示--> <link rel="icon" href="/favicon.png& ...
- 安卓JNI精细化讲解,让你彻底了解JNI(一):环境搭建与HelloWord
目录 1.基础概念 ├──1.1.JNI ├──1.2.NDK ├──1.3.CMake与ndk-build 2.环境搭建 3.Native C++ 项目(HelloWord案例) ├── 3.1.项 ...
- paper sharing :学习特征演化的数据流
特征演化的数据流 数据流学习是近年来机器学习与数据挖掘领域的一个热门的研究方向,数据流的场景和静态数据集的场景最大的一个特点就是数据会发生演化,关于演化数据流的研究大多集中于概念漂移检测(有监督学习) ...
- python:爬虫1——实战(下载一张图片、用Python模拟浏览器,通过在线的有道词典来对文本翻译)
一.下载一只猫 import urllib.request response = urllib.request.urlopen("http://cdn.duitang.com/uploads ...
- scrapy_redis分布式爬虫
文章来源:https://github.com/rmax/scrapy-redis Scrapy-Redis Documentation: https://scrapy-redis.readthedo ...