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 提供两个服务

  • 获取所有产品集合
  • 添加产品
  1. 使用 ASP.Net Core 创建 ProductService ,具体参考源码

  2. Dapr 启动 ProductService

    dapr run --app-id productService --app-port 5000 dotnet run
  3. 获取所有产品集合,使用 curl 命令

    curl -X GET http://localhost:5000/getlist

    或者

    curl -X GET http://localhost:54680/v1.0/invoke/productService/method/getlist
  4. 添加一个产品

    curl -X POST https://localhost:5001/product -H "Content-Type: application/json" -d "{ \"id\": \"14a3611d-1561-455f-9c72-381eed2f6ee3\" }"
  5. 重点,通过 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

  1. 创建 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
    }
  2. 使用 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

  1. 使用 NuGet 获取程序管理包控制台安装以下包

    • Dapr.AspNetCore
    • Dapr.Client.Grpc
    • Grpc.AspNetCore
    • Grpc.Net.Client
    • Grpc.Tools
  2. 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();
    });
    }
  3. 添加 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;
    }
    }
    }
  4. 使用 Dapr cli 启用 StorageService 服务

    dapr run --app-id storageService --app-port 5003 dotnet run
  5. 使用 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 运用的更多相关文章

  1. 技术分享:Dapr,让开发人员更轻松地构建微服务应用

    最近一直在学习微服务相关的技术.微服务架构已成为构建云原生应用程序的标准,并且可以预见,到2022年,将有90%的新应用程序采用微服务架构.微服务架构提供了令人信服的好处,包括可伸缩性,松散的服务耦合 ...

  2. 微软的分布式应用框架 Dapr Helloworld

    Dapr HelloWorld Dapr Distributed Application Runtime. An event-driven, portable runtime for building ...

  3. 微软的分布式应用框架 Dapr

    微服务架构已成为构建云原生应用程序的标准,微服务架构提供了令人信服的好处,包括可伸缩性,松散的服务耦合和独立部署,但是这种方法的成本很高,需要了解和熟练掌握分布式系统.为了使用所有开发人员能够使用任何 ...

  4. dapr微服务.netcore sdk入门

    Actors入门 先决条件 .Net Core SDK 3.0 Dapr CLI Dapr DotNet SDK 概述 本文档描述如何在客户端应用程序上创建Actor(MyActor)并调用其方法. ...

  5. Dapr 运用之 Java gRPC 调用篇

    JAVA GRPC 服务与调用 安装协议编译器 下载对应的版本编译器,并把路径加入到环境变量中,执行以下命令生成代码 protoc -I=$SRC_DIR --java_out=$DST_DIR $S ...

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

    前置条件: <Dapr 运用> 改造 ProductService 以提供 gRPC 服务 从 NuGet 或程序包管理控制台安装 gRPC 服务必须的包 Grpc.AspNetCore ...

  7. .NetCore集成Dapr踩坑经历

    该篇内容由个人博客点击跳转同步更新!转载请注明出处 前言 之前自己有个core2.2的项目一直是用的Surging作为微服务框架的,后来了解到了Dapr,发现比较轻量级,开发部署等也非常方便,故将自己 ...

  8. Dapr Pub/Sub 集成 RabbitMQ 、Golang、Java、DotNet Core

    前置条件: <Dapr运用> <Dapr 运用之 Java gRPC 调用篇> <Dapr 运用之集成 Asp.Net Core Grpc 调用篇> 搭建 Rabb ...

  9. Dapr实现分布式有状态服务的细节

    Dapr是为云上环境设计的跨语言, 事件驱动, 可以便捷的构建微服务的系统. balabala一堆, 有兴趣的小伙伴可以去了解一下. Dapr提供有状态和无状态的微服务. 大部分人都是做无状态服务(微 ...

随机推荐

  1. nginx跨域解决方案

    nginx跨域解决方案Access to Font at 'http://47.104.86.187/yinjiatoupiao2/iconfont/iconfont.woff' from origi ...

  2. mysql忘记密码怎么办??

    1.停掉mysql 1.1单实例停止方式 [root@qiuhom ~]# /etc/init.d/mysqld stop Shutting down MySQL. [ OK ] 1.2多实例停止方式 ...

  3. Jenkins初体验-安装与部署服务

    一.概述 1.简介 在工作中接触到CD/CI,Devops相关的技术,本文记录Jenkins的基本使用.Jenkins是一款开源的持续集成工具,能够集成一套自动化部署任务. 目标 通过jenkins从 ...

  4. redis 底层数据结构

    简单动态字符串SDS 包含字符串长度,剩余可用长度,字符数组 用于Redis中所有的string存储 字典(map) 数组+链表形式,跟hashMap很像 链地址法解决hash冲突 rehash使用新 ...

  5. SqlServer2005 查询 第五讲 top

    今天我们来说sql命令中得参数top top top[ 最前面若干个记录,专属于SqlServer2005的语法,不可移植到其他库.oracle中是用rownum<6来实现输出前5行记录.] 下 ...

  6. Spring框架学习笔记(7)——Spring Boot 实现上传和下载

    最近忙着都没时间写博客了,做了个项目,实现了下载功能,没用到上传,写这篇文章也是顺便参考学习了如何实现上传,上传和下载做一篇笔记吧 下载 主要有下面的两种方式: 通过ResponseEntity实现 ...

  7. Python日志模块logging简介

    日志处理是项目的必备功能,配置合理的日志,可以帮助我们了解系统的运行状况.定位位置,辅助数据分析技术,还可以挖掘出一些额外的系统信息. 本文介绍Python内置的日志处理模块logging的常见用法. ...

  8. Maven系列第8篇:你的maven项目构建太慢了,我实在看不下去,带你一起磨刀!!多数使用maven的人都经常想要的一种功能,但是大多数人都不知道如何使用!!!

    maven系列目标:从入门开始开始掌握一个高级开发所需要的maven技能. 这是maven系列第8篇. 整个maven系列的内容前后是有依赖的,如果之前没有接触过maven,建议从第一篇看起,本文尾部 ...

  9. nyoj 92-图像有用区域 (BFS)

    92-图像有用区域 内存限制:64MB 时间限制:3000ms 特判: No 通过数:4 提交数:12 难度:4 题目描述: “ACKing”同学以前做一个图像处理的项目时,遇到了一个问题,他需要摘取 ...

  10. python--几种快速排序的实现以及运行时间比较

    快速排序的基本思想:首先选定一个数组中的一个初始值,将数组中比该值小的放在左边,比该值大的放在右边,然后分别对左边的数组进行如上的操作,对右边的数组进行如上的操作.(分治+递归) 1.利用匿名函数la ...