1 - IDE 支持
1.1 - Visual Studio Code 与 Dapr 集成
1.1.1 - Dapr Visual Studio Code 扩展概述
弃用通知
该扩展先前由 Microsoft 支持,但现在已被弃用。该扩展将在 Visual Studio Code marketplace 中保持可用,但将不再接收更新或支持。用于本地开发的已弃用 Dapr Visual Studio Code 扩展 为用户提供了多种功能,以更好地管理其 Dapr 应用程序,并对所有支持的 Dapr 语言(包括 .NET、Go、PHP、Python 和 Java)的应用程序进行调试。
功能
脚手架 Dapr 调试任务
Dapr 扩展帮助你使用 Visual Studio Code 的内置调试功能通过 Dapr 调试应用程序。
使用 Dapr: Scaffold Dapr Tasks 命令面板操作,你可以更新现有的 task.json 和 launch.json 文件,以便在开始调试时启动和配置 Dapr 边车。
- 确保已为你的应用设置了启动配置。(了解更多)
- 使用
Ctrl+Shift+P打开命令面板 - 选择
Dapr: Scaffold Dapr Tasks - 使用
F5或通过运行视图运行你的应用和 Dapr 边车。
脚手架 Dapr 组件
将 Dapr 添加到应用程序时,你可能需要一个专用的组件目录,与作为 dapr init 一部分初始化的默认组件分离。
要创建包含默认 statestore、pubsub 和 zipkin 组件的专用组件文件夹,请使用 Dapr: Scaffold Dapr Components 命令面板操作。
- 在 Visual Studio Code 中打开应用程序目录
- 使用
Ctrl+Shift+P打开命令面板 - 选择
Dapr: Scaffold Dapr Components - 使用
dapr run --resources-path ./components -- ...运行应用程序
查看正在运行的 Dapr 应用程序
应用程序视图显示在本地机器上运行的 Dapr 应用程序。

调用 Dapr 应用程序
在应用程序视图中,用户可以右键单击并通过 GET 或 POST 方法调用 Dapr 应用程序,可选择指定有效负载。

向 Dapr 应用程序发布事件
在应用程序视图中,用户可以右键单击并向正在运行的 Dapr 应用程序发布消息,指定主题和有效负载。
用户还可以向所有正在运行的应用程序发布消息。

其他资源
同时调试多个 Dapr 应用程序
使用 VS Code 扩展,你可以通过多目标调试同时调试多个 Dapr 应用程序。
社区通话演示
观看此视频了解如何使用 Dapr VS Code 扩展:
1.1.2 - 如何操作:使用 Visual Studio Code 调试 Dapr 应用程序
弃用通知
该扩展此前由 Microsoft 支持,但现已弃用。该扩展在 Visual Studio Code marketplace 中仍然可用,但将不再接收更新或支持。手动调试
开发 Dapr 应用程序时,通常使用 Dapr CLI 启动 daprized 服务,类似这样:
dapr run --app-id nodeapp --app-port 3000 --dapr-http-port 3500 app.js
将调试器附加到服务的一种方法是首先在命令行中使用正确参数运行 daprd,然后启动代码并附加调试器。虽然这是一个完全可接受的解决方案,但它确实需要一些额外的步骤,并且需要向可能想要克隆你的仓库并点击"播放"按钮开始调试的开发者提供一些指导。
如果你的应用程序是一组微服务,每个都有 Dapr 边车,在 Visual Studio Code 中一起调试它们将非常有用。本页面将使用 hello world 快速入门来展示如何配置 VSCode 以使用 VSCode 调试来调试多个 Dapr 应用程序。
前提条件
- 安装 Dapr 扩展。稍后你将使用它提供的 任务。
- 可选:克隆 hello world 快速入门
步骤 1:配置 launch.json
文件 .vscode/launch.json 包含 VS Code 调试运行的 启动配置。该文件定义了当用户开始调试时将启动什么以及如何配置。Visual Studio Code marketplace中提供了每种编程语言的配置。
在 hello world 快速入门的情况下,启动了两个应用程序,每个都有自己的 Dapr 边车。一个用 Node.JS 编写,另一个用 Python 编写。你会注意到每个配置都包含一个 daprd run preLaunchTask 和一个 daprd stop postDebugTask。
{
"version": "0.2.0",
"configurations": [
{
"type": "pwa-node",
"request": "launch",
"name": "Nodeapp with Dapr",
"skipFiles": [
"<node_internals>/**"
],
"program": "${workspaceFolder}/node/app.js",
"preLaunchTask": "daprd-debug-node",
"postDebugTask": "daprd-down-node"
},
{
"type": "python",
"request": "launch",
"name": "Pythonapp with Dapr",
"program": "${workspaceFolder}/python/app.py",
"console": "integratedTerminal",
"preLaunchTask": "daprd-debug-python",
"postDebugTask": "daprd-down-python"
}
]
}
如果你使用的端口不是代码中内置的默认端口,请在 launch.json 调试配置中设置 DAPR_HTTP_PORT 和 DAPR_GRPC_PORT 环境变量。与 daprd tasks.json 中的 httpPort 和 grpcPort 匹配。例如,launch.json:
{
// 设置非默认的 HTTP 和 gRPC 端口
"env": {
"DAPR_HTTP_PORT": "3502",
"DAPR_GRPC_PORT": "50002"
},
}
tasks.json:
{
// 与 launch.json 中设置的端口匹配
"httpPort": 3502,
"grpcPort": 50002
}
每个配置都需要 request、type 和 name。这些参数帮助 VSCode 识别 .vscode/tasks.json 文件中的任务配置。
type定义使用的语言。根据语言的不同,它可能需要在 marketplace 中找到的扩展,例如 Python 扩展。name是配置的唯一名称。当在项目中调用多个配置时,这用于复合配置。${workspaceFolder}是 VS Code 变量引用。这是在 VS Code 中打开的工作区路径。preLaunchTask和postDebugTask参数指的是在启动应用程序之前和之后运行的程序配置。有关如何配置这些参数,请参阅步骤 2。
有关 VSCode 调试参数的更多信息,请参阅 VS Code 启动属性。
步骤 2:配置 tasks.json
对于 .vscode/launch.json 中定义的每个任务,在 .vscode/tasks.json 中必须存在相应的任务定义。
对于快速入门,每个服务都需要一个任务来使用 daprd 类型启动 Dapr 边车,以及一个使用 daprd-down 停止边车的任务。参数 appId、httpPort、metricsPort、label 和 type 是必需的。其他可选参数可用,请参阅此处的参考表。
{
"version": "2.0.0",
"tasks": [
{
"label": "daprd-debug-node",
"type": "daprd",
"appId": "nodeapp",
"appPort": 3000,
"httpPort": 3500,
"metricsPort": 9090
},
{
"label": "daprd-down-node",
"type": "daprd-down",
"appId": "nodeapp"
},
{
"label": "daprd-debug-python",
"type": "daprd",
"appId": "pythonapp",
"httpPort": 53109,
"grpcPort": 53317,
"metricsPort": 9091
},
{
"label": "daprd-down-python",
"type": "daprd-down",
"appId": "pythonapp"
}
]
}
步骤 3:在 launch.json 中配置复合启动
复合启动配置可以在 .vscode/launch.json 中定义,它是一组并行启动的两个或多个启动配置。可选地,可以指定 preLaunchTask 并在单独的调试会话开始之前运行。
对于此示例,复合配置是:
{
"version": "2.0.0",
"configurations": [...],
"compounds": [
{
"name": "Node/Python Dapr",
"configurations": ["Nodeapp with Dapr","Pythonapp with Dapr"]
}
]
}
步骤 4:启动调试会话
现在,你可以在 VS Code 调试器中找到在上一步中定义的复合命令名称,以调试模式运行应用程序:

你现在正在使用 Dapr 调试多个应用程序!
Daprd 参数表
以下是 VS Code 任务支持的参数。这些参数等同于 daprd 参数,详见此参考:
| 参数 | 描述 | 必需 | 示例 |
|---|---|---|---|
allowedOrigins | 允许的 HTTP 源(默认为 “*") | 否 | "allowedOrigins": "*" |
appId | 应用程序的唯一 ID。用于服务发现、状态封装和发布订阅消费者 ID | 是 | "appId": "divideapp" |
appMaxConcurrency | 限制应用程序的并发性。有效值是任何大于 0 的数字 | 否 | "appMaxConcurrency": -1 |
appPort | 此参数告诉 Dapr 你的应用程序正在监听哪个端口 | 是 | "appPort": 4000 |
appProtocol | 告诉 Dapr 你的应用程序使用哪个协议。有效选项是 http、grpc、https、grpcs、h2c。默认是 http。 | 否 | "appProtocol": "http" |
args | 设置传递给 Dapr 应用程序的参数列表 | 否 | “args”: [] |
componentsPath | 组件目录的路径。如果为空,则不会加载组件。 | 否 | "componentsPath": "./components" |
config | 告诉 Dapr 使用哪个配置资源 | 否 | "config": "./config" |
controlPlaneAddress | Dapr 控制平面的地址 | 否 | "controlPlaneAddress": "http://localhost:1366/" |
enableProfiling | 启用性能分析 | 否 | "enableProfiling": false |
enableMtls | 为 daprd 到 daprd 通信通道启用自动 mTLS | 否 | "enableMtls": false |
grpcPort | Dapr API 要监听的 gRPC 端口(默认为 “50001”) | 如果有多个应用则为是 | "grpcPort": 50004 |
httpPort | Dapr API 的 HTTP 端口 | 是 | "httpPort": 3502 |
internalGrpcPort | Dapr 内部 API 要监听的 gRPC 端口 | 否 | "internalGrpcPort": 50001 |
logAsJson | 将此参数设置为 true 会以 JSON 格式输出日志。默认为 false | 否 | "logAsJson": false |
logLevel | 设置 Dapr 边车的日志级别。允许的值是 debug、info、warn、error。默认是 info | 否 | "logLevel": "debug" |
metricsPort | 设置边车指标服务器的端口。默认为 9090 | 如果有多个应用则为是 | "metricsPort": 9093 |
mode | Dapr 的运行模式(默认为 “standalone”) | 否 | "mode": "standalone" |
placementHostAddress | Dapr Actor Placement 服务器的地址 | 否 | "placementHostAddress": "http://localhost:1313/" |
profilePort | 分析服务器的端口(默认为 “7777”) | 否 | "profilePort": 7777 |
sentryAddress | Sentry CA 服务的地址 | 否 | "sentryAddress": "http://localhost:1345/" |
type | 告诉 VS Code 这将是一个 daprd 任务类型 | 是 | "type": "daprd" |
相关链接
1.1.3 - 使用 Dev Containers 开发 Dapr 应用程序
弃用通知
该扩展此前由 Microsoft 支持,但现已弃用。该扩展仍将在 Visual Studio Code marketplace 中提供,但将不再接收更新或支持。Visual Studio Code Dev Containers 扩展允许您使用独立的 Docker 容器作为完整的开发环境,而无需在本地文件系统中安装任何额外的软件包、库或工具。
Dapr 为 C# 和 JavaScript/TypeScript 提供了预构建的 Dev Containers;您可以选择适合您需求的容器,即可获得现成的开发环境。请注意,这些预构建的容器会自动更新到最新的 Dapr 版本。
我们还发布了一个 Dev Container 功能,可在任何 Dev Container 中安装 Dapr CLI。
设置开发环境
前置条件
使用 Dev Container 功能添加 Dapr CLI
您可以使用 Dev Container 功能 在任何 Dev Container 中安装 Dapr CLI。
为此,请编辑您的 devcontainer.json 并在 "features" 部分添加两个对象:
"features": {
// 安装 Dapr CLI
"ghcr.io/dapr/cli/dapr-cli:0": {},
// 启用 Docker(通过 Docker-in-Docker)
"ghcr.io/devcontainers/features/docker-in-docker:2": {},
// 或者,使用 Docker-outside-of-Docker(使用主机上的 Docker)
//"ghcr.io/devcontainers/features/docker-outside-of-docker:1": {},
}
保存 JSON 文件并(重新)构建承载您的开发环境的容器后,您将拥有 Dapr CLI(和 Docker)可用,并且可以通过在容器中运行以下命令来安装 Dapr:
dapr init
示例:为 Dapr 创建 Java Dev Container
这是一个基于官方 Java 17 Dev Container 镜像创建用于开发使用 Dapr 的 Java 应用程序的 Dev Container 示例。
将此内容放在项目中的 .devcontainer/devcontainer.json 文件中:
// 有关格式详细信息,请参阅 https://aka.ms/devcontainer.json。有关配置选项,请参阅
// README at: https://github.com/devcontainers/templates/tree/main/src/java
{
"name": "Java",
// 或使用 Dockerfile 或 Docker Compose 文件。更多信息:https://containers.dev/guide/dockerfile
"image": "mcr.microsoft.com/devcontainers/java:0-17",
"features": {
"ghcr.io/devcontainers/features/java:1": {
"version": "none",
"installMaven": "false",
"installGradle": "false"
},
// 安装 Dapr CLI
"ghcr.io/dapr/cli/dapr-cli:0": {},
// 启用 Docker(通过 Docker-in-Docker)
"ghcr.io/devcontainers/features/docker-in-docker:2": {},
// 或者,使用 Docker-outside-of-Docker(使用主机上的 Docker)
//"ghcr.io/devcontainers/features/docker-outside-of-docker:1": {},
}
// 使用 'forwardPorts' 使容器内的端口列表在本地可用。
// "forwardPorts": [],
// 使用 'postCreateCommand' 在容器创建后运行命令。
// "postCreateCommand": "java -version",
// 配置特定于工具的属性。
// "customizations": {},
// 取消注释以 root 用户身份连接。更多信息:https://aka.ms/dev-containers-non-root。
// "remoteUser": "root"
}
然后,使用 VS Code 命令面板(CTRL + SHIFT + P 或 Mac 上的 CMD + SHIFT + P),选择 Dev Containers: Rebuild and Reopen in Container。
使用预构建的 Dev Container(C# 和 JavaScript/TypeScript)
- 在 VS Code 中打开您的应用程序工作区
- 在命令面板中(
CTRL + SHIFT + P或 Mac 上的CMD + SHIFT + P)键入并选择Dev Containers: Add Development Container Configuration Files...
- 键入
dapr以过滤列表到可用的 Dapr 远程容器,并选择与您的应用程序匹配的语言容器。请注意,您可能需要选择Show All Definitions...
- 按照提示在容器中重新打开您的工作区。

示例
观看此视频,了解如何将 Dapr Dev Containers 与您的应用程序一起使用。
1.2 - IntelliJ
在开发 Dapr 应用程序时,通常使用 Dapr CLI 启动您的"Dapr 化"服务,类似这样:
dapr run --app-id nodeapp --app-port 3000 --dapr-http-port 3500 app.js
这会使用默认的组件 yaml 文件(在 dapr init 时创建),以便您的服务可以与本地 Redis 容器交互。这对刚入门来说很好,但如果您想将调试器附加到您的服务并单步调试代码呢?这是您可以不调用应用程序而使用 dapr cli 的地方。
将调试器附加到服务的一种方法是首先从命令行运行 dapr run --,然后启动代码并附加调试器。虽然这是一个完全可以接受的解决方案,但它确实需要一些额外的步骤(比如在终端和 IDE 之间切换),以及一些可能想要克隆您的仓库并点击"播放"按钮开始调试的开发者说明。
本文档解释如何直接从 IntelliJ 使用 dapr。作为先决条件,请确保您已通过 dapr init 初始化了 Dapr 的开发环境。
让我们开始吧!
将 Dapr 添加为"外部工具"
首先,在直接修改配置文件之前退出 IntelliJ。
IntelliJ 配置文件位置
对于 2020.1 及更高版本,工具的配置文件应位于:
%USERPROFILE%\AppData\Roaming\JetBrains\IntelliJIdea2020.1\tools\
$HOME/.config/JetBrains/IntelliJIdea2020.1/tools/
~/Library/Application\ Support/JetBrains/IntelliJIdea2020.1/tools/
对于 2019.3 或更早版本,配置文件位置不同。有关更多详细信息,请参阅此处。
如果需要,请更改路径中 IntelliJ 的版本。
在 <CONFIG PATH>/tools/External\ Tools.xml 中创建或编辑文件(如果需要,更改路径中的 IntelliJ 版本)。<CONFIG PATH> 取决于操作系统,如上所示。
添加新的 <tool></tool> 条目:
<toolSet name="External Tools">
...
<!-- 1. 每个工具都有自己的 app-id,因此为每个要调试的应用程序创建一个 -->
<tool name="dapr for DemoService in examples" description="Dapr sidecar" showInMainMenu="false" showInEditor="false" showInProject="false" showInSearchPopup="false" disabled="false" useConsole="true" showConsoleOnStdOut="true" showConsoleOnStdErr="true" synchronizeAfterRun="true">
<exec>
<!-- 2. 对于 Linux 或 MacOS 使用:/usr/local/bin/dapr -->
<option name="COMMAND" value="C:\dapr\dapr.exe" />
<!-- 3. 选择不与其他 daprd 命令条目冲突的应用程序、http 和 grpc 端口(placement 地址不应更改)。 -->
<option name="PARAMETERS" value="run -app-id demoservice -app-port 3000 -dapr-http-port 3005 -dapr-grpc-port 52000" />
<!-- 4. 使用 `components` 文件夹所在的文件夹 -->
<option name="WORKING_DIRECTORY" value="C:/Code/dapr/java-sdk/examples" />
</exec>
</tool>
...
</toolSet>
(可选)您还可以为可以在许多项目中重用的边车工具创建新条目:
<toolSet name="External Tools">
...
<!-- 1. 具有应用端口的应用程序的可重用条目。 -->
<tool name="dapr with app-port" description="Dapr sidecar" showInMainMenu="false" showInEditor="false" showInProject="false" showInSearchPopup="false" disabled="false" useConsole="true" showConsoleOnStdOut="true" showConsoleOnStdErr="true" synchronizeAfterRun="true">
<exec>
<!-- 2. 对于 Linux 或 MacOS 使用:/usr/local/bin/dapr -->
<option name="COMMAND" value="c:\dapr\dapr.exe" />
<!-- 3. 提示用户 4 次(按顺序):app id、app port、Dapr 的 http port、Dapr 的 grpc port。 -->
<option name="PARAMETERS" value="run --app-id $Prompt$ --app-port $Prompt$ --dapr-http-port $Prompt$ --dapr-grpc-port $Prompt$" />
<!-- 4. 使用 `components` 文件夹所在的文件夹 -->
<option name="WORKING_DIRECTORY" value="$ProjectFileDir$" />
</exec>
</tool>
<!-- 1. 没有 app-port 的应用程序的可重用条目。 -->
<tool name="dapr without app-port" description="Dapr sidecar" showInMainMenu="false" showInEditor="false" showInProject="false" showInSearchPopup="false" disabled="false" useConsole="true" showConsoleOnStdOut="true" showConsoleOnStdErr="true" synchronizeAfterRun="true">
<exec>
<!-- 2. 对于 Linux 或 MacOS 使用:/usr/local/bin/dapr -->
<option name="COMMAND" value="c:\dapr\dapr.exe" />
<!-- 3. 提示用户 3 次(按顺序):app id、Dapr 的 http port、Dapr 的 grpc port。 -->
<option name="PARAMETERS" value="run --app-id $Prompt$ --dapr-http-port $Prompt$ --dapr-grpc-port $Prompt$" />
<!-- 4. 使用 `components` 文件夹所在的文件夹 -->
<option name="WORKING_DIRECTORY" value="$ProjectFileDir$" />
</exec>
</tool>
...
</toolSet>
创建或编辑运行配置
现在,为要调试的应用程序创建或编辑运行配置。可以在 main() 函数旁边的菜单中找到它。

现在,添加程序参数和环境变量。这些需要与上面"外部工具"中的条目定义的端口匹配。
- 本示例的命令行参数:
-p 3000 - 本示例的环境变量:
DAPR_HTTP_PORT=3005;DAPR_GRPC_PORT=52000

开始调试
完成上述一次性配置后,在 IntelliJ 中使用 Dapr 调试 Java 应用程序需要两个步骤:
- 通过 IntelliJ 中的
Tools->External Tool启动dapr。

- 以调试模式启动您的应用程序。

总结
调试完成后,请确保在 IntelliJ 中同时停止 dapr 和您的应用程序。
注意:由于您使用 dapr run CLI 命令启动了服务,dapr list 命令将在当前使用 Dapr 运行的应用程序列表中显示来自 IntelliJ 的运行。
祝您调试愉快!
相关链接
- IntelliJ 配置目录位置的更改
2 - 多应用运行
2.1 - Multi-App Run 概述
Note
适用于 Kubernetes 的 Multi-App Run 目前为预览功能。假设您想在本地运行多个应用程序以进行联合测试,类似于生产环境的场景。Multi-App Run 允许您同时启动和停止一组应用程序,可以选择:
- 使用进程在本地/自托管环境中运行,或
- 通过构建容器镜像并部署到 Kubernetes 集群
- 您可以使用本地 Kubernetes 集群或部署到云
Multi-App Run 模板文件描述了如何启动多个应用程序,就像您执行了多个单独的 CLI run 命令一样。默认情况下,此模板文件名为 dapr.yaml。
Multi-App Run 模板文件
当您执行 dapr run -f . 时,它会启动当前目录中存在的多应用模板文件(名为 dapr.yaml)以运行所有应用程序。
您可以使用首选名称来命名模板文件,而不是使用默认名称。例如 dapr run -f ./<your-preferred-file-name>.yaml。
以下示例包括一些您可以为应用程序自定义的模板属性。在该示例中,您可以同时启动 2 个应用程序,其应用 ID 为 processor 和 emit-metrics。
version: 1
apps:
- appID: processor
appDirPath: ../apps/processor/
appPort: 9081
daprHTTPPort: 3510
command: ["go","run", "app.go"]
- appID: emit-metrics
appDirPath: ../apps/emit-metrics/
daprHTTPPort: 3511
env:
DAPR_HOST_ADD: localhost
command: ["go","run", "app.go"]
有关更深入的示例和模板属性的解释,请参阅 多应用模板。
资源和配置文件的位置
在使用 Multi-App Run 时,您可以选择放置应用程序资源和配置文件的位置。
指向一个文件位置(使用约定)
您可以在 ~/.dapr 根目录下设置所有应用程序资源和配置。当所有应用程序共享相同的资源路径时(例如在本地机器上测试时),这很有帮助。
为每个应用程序指定单独的文件位置(使用约定)
使用 Multi-App Run 时,每个应用程序目录可以有一个 .dapr 文件夹,其中包含 config.yaml 文件和 resources 目录。否则,如果应用程序目录中不存在 .dapr 目录,则使用默认的 ~/.dapr/resources/ 和 ~/.dapr/config.yaml 位置。
如果您决定在每个应用程序目录中添加 .dapr 目录,其中包含 /resources 目录和 config.yaml 文件,则可以为每个应用程序指定不同的资源路径。此方法通过使用默认的 ~/.dapr 保持约定。
指向单独的位置(自定义)
您还可以将每个应用目录的 .dapr 目录命名为 .dapr 以外的名称,例如 webapp 或 backend。如果您想明确资源或应用程序目录路径,这很有帮助。
日志
运行模板为每个应用程序及其关联的 daprd 进程提供两个日志目标字段:
appLogDestination:此字段配置应用程序的日志目标。可能的值为console、file和fileAndConsole。默认值为fileAndConsole,其中应用程序日志默认写入控制台和文件。daprdLogDestination:此字段配置daprd进程的日志目标。可能的值为console、file和fileAndConsole。默认值为file,其中daprd日志默认写入文件。
日志文件格式
应用程序和 daprd 的日志捕获在单独的文件中。这些日志文件在应用程序目录(模板中的 appDirPath)下的 .dapr/logs 目录下自动创建。这些日志文件名遵循以下模式:
<appID>_app_<timestamp>.log(app日志的文件名格式)<appID>_daprd_<timestamp>.log(daprd日志的文件名格式)
即使您决定将资源文件夹重命名为 .dapr 以外的名称,日志文件也只会写入 .dapr/logs 文件夹(在应用程序目录中创建)。
观看演示
Multi-App Run 模板文件
当您执行 dapr run -k -f . 或 dapr run -k -f dapr.yaml 时,dapr.yaml Multi-App Run 模板文件中定义的应用程序将在 Kubernetes 默认命名空间中启动。
注意: 目前,Multi-App Run 模板只能在默认 Kubernetes 命名空间中启动应用程序。
Kubernetes 的必要默认服务和部署定义会在 .dapr/deploy 文件夹中为 dapr.yaml 模板中的每个应用程序生成。
如果在 dapr.yaml 模板中为某个应用程序将 createService 字段设置为 true,则会在该应用程序的 .dapr/deploy 文件夹中生成 service.yaml 文件。
否则,只为设置了 containerImage 字段的每个应用程序生成 deployment.yaml 文件。
service.yaml 和 deployment.yaml 文件用于在 Kubernetes 中的 default 命名空间中部署应用程序。此功能专门针对在 Kubernetes 中的开发/测试环境中运行多个应用程序。
您可以使用任何首选名称来命名模板文件,而不是使用默认名称。例如:
dapr run -k -f ./<your-preferred-file-name>.yaml
以下示例包括一些您可以为应用程序自定义的模板属性。在该示例中,您可以同时启动 2 个应用程序,其应用 ID 为 nodeapp 和 pythonapp。
version: 1
common:
apps:
- appID: nodeapp
appDirPath: ./nodeapp/
appPort: 3000
containerImage: ghcr.io/dapr/samples/hello-k8s-node:latest
containerImagePullPolicy: Always
createService: true
env:
APP_PORT: 3000
- appID: pythonapp
appDirPath: ./pythonapp/
containerImage: ghcr.io/dapr/samples/hello-k8s-python:latest
注意:
- 如果未指定
containerImage字段,dapr run -k -f会产生错误。- containerImagePullPolicy 表示始终为此应用程序下载新的容器镜像。
createService字段在 Kubernetes 中定义一个基本服务(ClusterIP 或 LoadBalancer),该服务针对模板中指定的--app-port。如果未指定createService,则应用程序无法从集群外部访问。
有关更深入的示例和模板属性的解释,请参阅 多应用模板。
日志
运行模板为每个应用程序及其关联的 daprd 进程提供两个日志目标字段:
appLogDestination:此字段配置应用程序的日志目标。可能的值为console、file和fileAndConsole。默认值为fileAndConsole,其中应用程序日志默认写入控制台和文件。daprdLogDestination:此字段配置daprd进程的日志目标。可能的值为console、file和fileAndConsole。默认值为file,其中daprd日志默认写入文件。
日志文件格式
应用程序和 daprd 的日志捕获在单独的文件中。这些日志文件在应用程序目录(模板中的 appDirPath)下的 .dapr/logs 目录下自动创建。这些日志文件名遵循以下模式:
<appID>_app_<timestamp>.log(app日志的文件名格式)<appID>_daprd_<timestamp>.log(daprd日志的文件名格式)
即使您决定将资源文件夹重命名为 .dapr 以外的名称,日志文件也只会写入 .dapr/logs 文件夹(在应用程序目录中创建)。
观看演示
后续步骤
2.2 - 操作指南:使用多应用运行模板文件
注意
Kubernetes 的多应用运行目前为预览功能。多应用运行模板文件是一个 YAML 文件,可用于一次运行多个应用程序。在本指南中,您将学习如何:
- 使用多应用模板
- 查看已启动的应用程序
- 停止多应用模板
- 构建多应用模板文件结构
使用多应用模板
您可以通过以下两种方式之一使用多应用模板文件:
通过提供目录路径执行
当您提供目录路径时,CLI 将尝试在目录中查找名为 dapr.yaml(默认名称)的多应用运行模板文件。如果未找到该文件,CLI 将返回错误。
执行以下 CLI 命令以读取多应用运行模板文件,默认名称为 dapr.yaml:
# 如果给定目录路径,模板文件需要默认命名为 `dapr.yaml`
dapr run -f <dir_path>
dapr run -f <dir_path> -k
通过提供文件路径执行
如果多应用运行模板文件的名称不是 dapr.yaml,那么您可以向命令提供相对或绝对文件路径:
dapr run -f ./path/to/<your-preferred-file-name>.yaml
dapr run -f ./path/to/<your-preferred-file-name>.yaml -k
查看已启动的应用程序
多应用模板运行后,您可以使用以下命令查看已启动的应用程序:
dapr list
dapr list -k
停止多应用模板
随时使用以下任一命令停止多应用运行模板:
# 如果给定目录路径,模板文件需要默认命名为 `dapr.yaml`
dapr stop -f <dir_path>
或:
dapr stop -f ./path/to/<your-preferred-file-name>.yaml
# 如果给定目录路径,模板文件需要默认命名为 `dapr.yaml`
dapr stop -f <dir_path> -k
或:
dapr stop -f ./path/to/<your-preferred-file-name>.yaml -k
模板文件结构
多应用运行模板文件可以包含以下属性。以下是一个示例模板,展示了配置了部分属性的两个应用程序。
version: 1
common: # 可选部分,用于在应用程序之间共享的变量
resourcesPath: ./app/components # 任何在应用程序之间共享的 dapr 资源
env: # 任何在应用程序之间共享的环境变量
DEBUG: true
apps:
- appID: webapp # 可选
appDirPath: .dapr/webapp/ # 必需
resourcesPath: .dapr/resources # 已弃用
resourcesPaths: .dapr/resources # 逗号分隔的资源路径。(可选)可按约定保留为默认值。
appChannelAddress: 127.0.0.1 # 应用程序监听的网络地址。(可选)可按约定保留为默认值。
configFilePath: .dapr/config.yaml # (可选)也可以按约定默认,如果未找到文件则忽略。
appProtocol: http
appPort: 8080
appHealthCheckPath: "/healthz"
command: ["python3", "app.py"]
appLogDestination: file # (可选),可以是 file、console 或 fileAndConsole。默认为 fileAndConsole。
daprdLogDestination: file # (可选),可以是 file、console 或 fileAndConsole。默认为 file。
- appID: backend # 可选
appDirPath: .dapr/backend/ # 必需
appProtocol: grpc
appPort: 3000
unixDomainSocket: "/tmp/test-socket"
env:
DEBUG: false
command: ["./backend"]
模板文件中所有路径适用以下规则:
- 如果路径是绝对路径,则按原样使用。
- common 部分下的所有相对路径应相对于模板文件路径提供。
- apps 部分下的
appDirPath应相对于模板文件路径提供。 - apps 部分下的所有其他相对路径应相对于
appDirPath提供。
version: 1
common: # 可选部分,用于在应用程序之间共享的变量
env: # 任何在应用程序之间共享的环境变量
DEBUG: true
apps:
- appID: webapp # 可选
appDirPath: .dapr/webapp/ # 必需
appChannelAddress: 127.0.0.1 # 应用程序监听的网络地址。(可选)可按约定保留为默认值。
appProtocol: http
appPort: 8080
appHealthCheckPath: "/healthz"
appLogDestination: file # (可选),可以是 file、console 或 fileAndConsole。默认为 fileAndConsole。
daprdLogDestination: file # (可选),可以是 file、console 或 fileAndConsole。默认为 file。
containerImage: ghcr.io/dapr/samples/hello-k8s-node:latest # (可选)部署到 Kubernetes 开发/测试环境时要使用的容器镜像 URI。
containerImagePullPolicy: IfNotPresent # (可选),如果本地不存在容器镜像则下载,否则使用本地镜像。
createService: true # (可选)部署到开发/测试环境时为应用程序创建 Kubernetes 服务。
- appID: backend # 可选
appDirPath: .dapr/backend/ # 必需
appProtocol: grpc
appPort: 3000
unixDomainSocket: "/tmp/test-socket"
env:
DEBUG: false
模板文件中所有路径适用以下规则:
- 如果路径是绝对路径,则按原样使用。
- apps 部分下的
appDirPath应相对于模板文件路径提供。 - app 部分下的所有相对路径应相对于
appDirPath提供。
模板属性
多应用运行模板的属性与 dapr run CLI 标志一致,在 CLI 参考文档中列出。
| 属性 | 必需 | 详情 | 示例 |
|---|---|---|---|
appDirPath | 是 | 应用程序代码的路径 | ./webapp/、./backend/ |
appID | 否 | 应用程序的 app ID。如果未提供,将从 appDirPath 派生 | webapp、backend |
resourcesPath | 否 | 已弃用。Dapr 资源的路径。可按约定使用默认值 | ./app/components、./webapp/components |
resourcesPaths | 否 | Dapr 资源的逗号分隔路径。可按约定使用默认值 | ./app/components、./webapp/components |
appChannelAddress | 否 | 应用程序监听的网络地址。可按约定保留为默认值。 | 127.0.0.1 |
configFilePath | 否 | 应用程序配置文件的路径 | ./webapp/config.yaml |
appProtocol | 否 | Dapr 用于与应用程序通信的协议。 | http、grpc |
appPort | 否 | 应用程序监听的端口 | 8080、3000 |
daprHTTPPort | 否 | Dapr HTTP 端口 | |
daprGRPCPort | 否 | Dapr GRPC 端口 | |
daprInternalGRPCPort | 否 | Dapr 内部 API 监听的 gRPC 端口;用于从本地 DNS 组件解析值时使用 | |
metricsPort | 否 | Dapr 将其指标信息发送到的端口 | |
unixDomainSocket | 否 | Unix 域套接字目录挂载的路径。如果指定,与 Dapr 边车的通信使用 Unix 域套接字,与使用 TCP 端口相比,具有更低的延迟和更高的吞吐量。在 Windows 上不可用。 | /tmp/test-socket |
profilePort | 否 | 性能分析服务器监听的端口 | |
enableProfiling | 否 | 通过 HTTP 端点启用性能分析 | |
apiListenAddresses | 否 | Dapr API 监听地址 | |
logLevel | 否 | 日志详细程度。 | |
appMaxConcurrency | 否 | 应用程序的并发级别;默认为无限制 | |
placementHostAddress | 否 | Dapr placement 服务器的逗号分隔地址列表 | 127.0.0.1:50057,127.0.0.1:50058 |
schedulerHostAddress | 否 | Dapr Scheduler Service 主机地址 | localhost:50006 |
appSSL | 否 | 当 Dapr 调用应用程序时启用 HTTPS | |
maxBodySize | 否 | 请求正文的最大大小(以 MB 为单位)。使用大小单位设置值(例如,16Mi 表示 16MB)。默认为 4Mi | |
readBufferSize | 否 | HTTP 读取缓冲区的最大大小(以 KB 为单位)。这也限制了 HTTP 标头的最大大小。使用大小单位设置值,例如 32Ki 将支持最大 32KB 的标头。默认为 4Ki(4KB) | |
enableAppHealthCheck | 否 | 在应用程序上启用应用程序运行状况检查 | true、false |
appHealthCheckPath | 否 | 运行状况检查文件的路径 | /healthz |
appHealthProbeInterval | 否 | 探测应用程序运行状况的间隔(以秒为单位) | |
appHealthProbeTimeout | 否 | 应用程序运行状况探测的超时时间(以毫秒为单位) | |
appHealthThreshold | 否 | 应用程序被视为不健康之前的连续失败次数 | |
enableApiLogging | 否 | 启用从应用程序到 Dapr 的所有 API 调用的日志记录 | |
runtimePath | 否 | Dapr 运行时安装路径 | |
env | 否 | 映射到环境变量;应用于每个应用程序的环境变量将覆盖在应用程序之间共享的环境变量 | DEBUG、DAPR_HOST_ADD |
appLogDestination | 否 | 用于输出应用程序日志的日志目标;其值可以是 file、console 或 fileAndConsole。默认为 fileAndConsole | file、console、fileAndConsole |
daprdLogDestination | 否 | 用于输出 daprd 日志的日志目标;其值可以是 file、console 或 fileAndConsole。默认为 file | file、console、fileAndConsole |
后续步骤
多应用运行模板的属性与 dapr run -k CLI 标志一致,在 CLI 参考文档中列出。
| 属性 | 必需 | 详情 | 示例 |
|---|---|---|---|
appDirPath | 是 | 应用程序代码的路径 | ./webapp/、./backend/ |
appID | 否 | 应用程序的 app ID。如果未提供,将从 appDirPath 派生 | webapp、backend |
appChannelAddress | 否 | 应用程序监听的网络地址。可按约定保留为默认值。 | 127.0.0、localhost |
appProtocol | 否 | Dapr 用于与应用程序通信的协议。 | http、grpc |
appPort | 否 | 应用程序监听的端口 | 8080、3000 |
daprHTTPPort | 否 | Dapr HTTP 端口 | |
daprGRPCPort | 否 | Dapr GRPC 端口 | |
daprInternalGRPCPort | 否 | Dapr 内部 API 监听的 gRPC 端口;用于从本地 DNS 组件解析值时使用 | |
metricsPort | 否 | Dapr 将其指标信息发送到的端口 | |
unixDomainSocket | 否 | Unix 域套接字目录挂载的路径。如果指定,与 Dapr 边车的通信使用 Unix 域套接字,与使用 TCP 端口相比,具有更低的延迟和更高的吞吐量。在 Windows 上不可用。 | /tmp/test-socket |
profilePort | 否 | 性能分析服务器监听的端口 | |
enableProfiling | 否 | 通过 HTTP 端点启用性能分析 | |
apiListenAddresses | 否 | Dapr API 监听地址 | |
logLevel | 否 | 日志详细程度。 | |
appMaxConcurrency | 否 | 应用程序的并发级别;默认为无限制 | |
placementHostAddress | 否 | Dapr placement 服务器的逗号分隔地址列表 | 127.0.0.1:50057,127.0.0.1:50058 |
schedulerHostAddress | 否 | Dapr Scheduler Service 主机地址 | 127.0.0.1:50006 |
appSSL | 否 | 当 Dapr 调用应用程序时启用 HTTPS | |
maxBodySize | 否 | 请求正文的最大大小(以 MB 为单位)。使用大小单位设置值(例如,16Mi 表示 16MB)。默认为 4Mi | 16Mi |
readBufferSize | 否 | HTTP 读取缓冲区的最大大小(以 KB 为单位)。这也限制了 HTTP 标头的最大大小。使用大小单位设置值,例如 32Ki 将支持最大 32KB 的标头。默认为 4Ki(4KB) | 32Ki |
enableAppHealthCheck | 否 | 在应用程序上启用应用程序运行状况检查 | true、false |
appHealthCheckPath | 否 | 运行状况检查文件的路径 | /healthz |
appHealthProbeInterval | 否 | 探测应用程序运行状况的间隔(以秒为单位) | |
appHealthProbeTimeout | 否 | 应用程序运行状况探测的超时时间(以毫秒为单位) | |
appHealthThreshold | 否 | 应用程序被视为不健康之前的连续失败次数 | |
enableApiLogging | 否 | 启用从应用程序到 Dapr 的所有 API 调用的日志记录 | |
env | 否 | 映射到环境变量;应用于每个应用程序的环境变量将覆盖在应用程序之间共享的环境变量 | DEBUG、DAPR_HOST_ADD |
appLogDestination | 否 | 用于输出应用程序日志的日志目标;其值可以是 file、console 或 fileAndConsole。默认为 fileAndConsole | file、console、fileAndConsole |
daprdLogDestination | 否 | 用于输出 daprd 日志的日志目标;其值可以是 file、console 或 fileAndConsole。默认为 file | file、console、fileAndConsole |
containerImage | 否 | 部署到 Kubernetes 开发/测试环境时要使用的容器镜像 URI。 | ghcr.io/dapr/samples/hello-k8s-python:latest |
containerImagePullPolicy | 否 | 容器镜像拉取策略(默认为 Always)。 | Always、IfNotPresent、Never |
createService | 否 | 部署到开发/测试环境时为应用程序创建 Kubernetes 服务。 | true、false |
后续步骤
3 - 操作指南:在 Dapr 应用中使用 gRPC 接口
Dapr 为本地调用实现了 HTTP 和 gRPC 两种 API。gRPC 适用于低延迟、高性能场景,并提供了基于 proto 客户端的语言集成。
Dapr 运行时实现了一个 proto 服务,应用程序可以通过 gRPC 与其通信。
除了通过 gRPC 调用 Dapr 外,Dapr 还支持作为代理进行 gRPC 服务间调用。在 gRPC 服务调用操作指南中了解更多。
本指南演示如何使用 Go SDK 应用程序配置并通过 gRPC 调用 Dapr。
配置 Dapr 通过 gRPC 与应用程序通信
在自托管模式下运行时,使用 --app-protocol 标志告知 Dapr 使用 gRPC 与应用程序通信。
dapr run --app-protocol grpc --app-port 5005 node app.js
这会告知 Dapr 通过端口 5005 上的 gRPC 与应用程序通信。
在 Kubernetes 上,在部署 YAML 中设置以下注解:
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
namespace: default
labels:
app: myapp
spec:
replicas: 1
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
annotations:
dapr.io/enabled: "true"
dapr.io/app-id: "myapp"
dapr.io/app-protocol: "grpc"
dapr.io/app-port: "5005"
...
通过 gRPC 调用 Dapr
以下步骤展示如何创建 Dapr 客户端并调用其 SaveStateData 操作。
导入包:
package main import ( "context" "log" "os" dapr "github.com/dapr/go-sdk/client" )创建客户端:
// 仅用于此演示 ctx := context.Background() data := []byte("ping") // 创建客户端 client, err := dapr.NewClient() if err != nil { log.Panic(err) } defer client.Close()- 调用
SaveState方法:
// 使用键 key1 保存状态 err = client.SaveState(ctx, "statestore", "key1", data) if err != nil { log.Panic(err) } log.Println("data saved")- 调用
现在你可以探索 Dapr 客户端上的所有不同方法。
使用 Dapr 创建 gRPC 应用
以下步骤展示如何创建一个应用程序,该应用程序暴露一个可供 Dapr 通信的服务器。
导入包:
package main import ( "context" "fmt" "log" "net" "github.com/golang/protobuf/ptypes/any" "github.com/golang/protobuf/ptypes/empty" commonv1pb "github.com/dapr/dapr/pkg/proto/common/v1" pb "github.com/dapr/dapr/pkg/proto/runtime/v1" "google.golang.org/grpc" )实现接口:
// server 是我们的用户应用程序 type server struct { pb.UnimplementedAppCallbackServer } // EchoMethod 是一个简单的演示方法,用于调用 func (s *server) EchoMethod() string { return "pong" } // 当远程服务通过 Dapr 调用应用程序时,会调用此方法 // 载荷包含一个用于标识方法的 Method、一组元数据属性和一个可选载荷 func (s *server) OnInvoke(ctx context.Context, in *commonv1pb.InvokeRequest) (*commonv1pb.InvokeResponse, error) { var response string switch in.Method { case "EchoMethod": response = s.EchoMethod() } return &commonv1pb.InvokeResponse{ ContentType: "text/plain; charset=UTF-8", Data: &any.Any{Value: []byte(response)}, }, nil } // Dapr 将调用此方法以获取应用程序希望订阅的主题列表。在此示例中,我们告知 Dapr // 订阅一个名为 TopicA 的主题 func (s *server) ListTopicSubscriptions(ctx context.Context, in *empty.Empty) (*pb.ListTopicSubscriptionsResponse, error) { return &pb.ListTopicSubscriptionsResponse{ Subscriptions: []*pb.TopicSubscription{ {Topic: "TopicA"}, }, }, nil } // Dapr 将调用此方法以获取将调用应用程序的绑定列表。在此示例中,我们告知 Dapr // 使用名为 storage 的绑定调用我们的应用程序 func (s *server) ListInputBindings(ctx context.Context, in *empty.Empty) (*pb.ListInputBindingsResponse, error) { return &pb.ListInputBindingsResponse{ Bindings: []string{"storage"}, }, nil } // 每当从已注册绑定触发新事件时,都会调用此方法。消息携带绑定名称、载荷和可选元数据 func (s *server) OnBindingEvent(ctx context.Context, in *pb.BindingEventRequest) (*pb.BindingEventResponse, error) { fmt.Println("Invoked from binding") return &pb.BindingEventResponse{}, nil } // 当消息已发布到已订阅的主题时,将触发此方法。Dapr 以 CloudEvents 0.3 信封发送已发布的消息。 func (s *server) OnTopicEvent(ctx context.Context, in *pb.TopicEventRequest) (*pb.TopicEventResponse, error) { fmt.Println("Topic message arrived") return &pb.TopicEventResponse{}, nil }创建服务器:
func main() { // 创建监听器 lis, err := net.Listen("tcp", ":50001") if err != nil { log.Fatalf("failed to listen: %v", err) } // 创建 grpc 服务器 s := grpc.NewServer() pb.RegisterAppCallbackServer(s, &server{}) fmt.Println("Client starting...") // 然后启动... if err := s.Serve(lis); err != nil { log.Fatalf("failed to serve: %v", err) } }这会为你的应用程序在端口 50001 上创建一个 gRPC 服务器。
运行应用程序
要在本地运行,请使用 Dapr CLI:
dapr run --app-id goapp --app-port 50001 --app-protocol grpc go run main.go
在 Kubernetes 上,在 Pod 规范模板中设置所需的 dapr.io/app-protocol: "grpc" 和 dapr.io/app-port: "50001 注解,如上所述。
其他语言
你可以将 Dapr 与 Protobuf 支持的任何语言一起使用,而不仅仅是当前可用的生成 SDK。
使用 protoc 工具,你可以为其他语言(如 Ruby、C++、Rust 等)生成 Dapr 客户端。
相关主题
4 - Dapr SDK 中的序列化
Dapr SDK 为两种用例提供序列化。首先,是通过请求和响应负载发送的 API 对象。其次,是需要持久化的对象。对于这两种情况,每种语言 SDK 都提供了默认的序列化方法。
| Language SDK | 默认序列化器 |
|---|---|
| .NET | 对于远程 actor 使用 DataContracts,其他情况使用 System.Text.Json。了解更多关于 .NET 序列化的信息 here |
| Java | 用于 JSON 序列化的 DefaultObjectSerializer |
| JavaScript | JSON |
服务调用
using var client = (new DaprClientBuilder()).Build();
await client.InvokeMethodAsync("myappid", "saySomething", "My Message");
DaprClient client = (new DaprClientBuilder()).build();
client.invokeMethod("myappid", "saySomething", "My Message", HttpExtension.POST).block();
在上面的示例中,应用 myappid 接收到一个 saySomething 方法的 POST 请求,请求负载为 "My Message" — 由于序列化器会将输入的 String 序列化为 JSON,所以它被引号包裹。
POST /saySomething HTTP/1.1
Host: localhost
Content-Type: text/plain
Content-Length: 12
"My Message"
状态管理
using var client = (new DaprClientBuilder()).Build();
var state = new Dictionary<string, string>
{
{ "key": "MyKey" },
{ "value": "My Message" }
};
await client.SaveStateAsync("MyStateStore", "MyKey", state);
DaprClient client = (new DaprClientBuilder()).build();
client.saveState("MyStateStore", "MyKey", "My Message").block();
在此示例中,My Message 被保存。它没有被引号包裹,因为 Dapr 的 API 在保存前会在内部解析 JSON 请求对象。
在此示例中,My Message 被保存。它没有被引号包裹,因为 Dapr 的 API 在发送前会在内部序列化字符串。
发布订阅
using var client = (new DaprClientBuilder()).Build();
await client.PublishEventAsync("MyPubSubName", "TopicName", "My Message");
事件被发布,内容被序列化为 byte[] 并发送到 Dapr 边车。订阅者将其作为 CloudEvent 接收。Cloud 事件将 data 定义为字符串。Dapr SDK 也为 CloudEvent 对象提供了内置的反序列化器。
public async Task<IActionResult> HandleMessage(string message)
{
//ASP.NET Core 自动将 UTF-8 编码的字节反序列化为字符串
return new Ok();
}
或者
app.MapPost("/TopicName", [Topic("MyPubSubName", "TopicName")] (string message) => {
return Results.Ok();
}
DaprClient client = (new DaprClientBuilder()).build();
client.publishEvent("TopicName", "My Message").block();
事件被发布,内容被序列化为 byte[] 并发送到 Dapr 边车。订阅者将其作为 CloudEvent 接收。Cloud 事件将 data 定义为 String。Dapr SDK 也为 CloudEvent 对象提供了内置的反序列化器。
@PostMapping(path = "/TopicName")
public void handleMessage(@RequestBody(required = false) byte[] body) {
// Dapr 的事件符合 CloudEvent 规范
CloudEvent event = CloudEvent.deserialize(body);
}
绑定
对于输出绑定,对象被序列化为 byte[],而输入绑定按原样接收原始 byte[] 并将其反序列化为预期的对象类型。
- 输出绑定:
using var client = (new DaprClientBuilder()).Build();
await client.InvokeBindingAsync("sample", "My Message");
- 输入绑定(控制器):
[ApiController]
public class SampleController : ControllerBase
{
[HttpPost("propagate")]
public ActionResult<string> GetValue([FromBody] int itemId)
{
Console.WriteLine($"Received message: {itemId}");
return $"itemID:{itemId}";
}
}
- 输入绑定(最小 API):
app.MapPost("value", ([FromBody] int itemId) =>
{
Console.WriteLine($"Received message: {itemId}");
return ${itemID:{itemId}";
});
- 输出绑定:
DaprClient client = (new DaprClientBuilder()).build();
client.invokeBinding("sample", "My Message").block();
- 输入绑定:
@PostMapping(path = "/sample")
public void handleInputBinding(@RequestBody(required = false) byte[] body) {
String message = (new DefaultObjectSerializer()).deserialize(body, String.class);
System.out.println(message);
}
它应该打印:
My Message
Actor 方法调用
Actor 方法调用的对象序列化和反序列化与服务方法调用的方式相同,唯一的区别是应用不需要反序列化请求或序列化响应,因为这一切都由 SDK 透明地完成。
对于 Actor 方法,SDK 仅支持具有零个或一个参数的方法。
根据您使用的是强类型还是弱类型客户端,.NET SDK 提供了不同的序列化选项:强类型客户端使用 DataContracts,而弱类型客户端可以选择 DataContracts 或 System.Text.JSON。您可以参考 [本文档](https://docs.dapr.io/zh-hans/developing-applications/sdks/dotnet/dotnet-actors/dotnet-actors-serialization/) 了解各种序列化方式之间的差异和需要注意的细节。- 使用弱类型客户端和 System.Text.JSON 调用 Actor 的方法:
var proxy = this.ProxyFactory.Create(ActorId.CreateRandom(), "DemoActor");
await proxy.SayAsync("My message");
- 实现 Actor 的方法:
public Task SayAsync(string message)
{
Console.WriteLine(message);
return Task.CompletedTask;
}
- 调用 Actor 的方法:
public static void main() {
ActorProxyBuilder builder = new ActorProxyBuilder("DemoActor");
String result = actor.invokeActorMethod("say", "My Message", String.class).block();
}
- 实现 Actor 的方法:
public String say(String something) {
System.out.println(something);
return "OK";
}
它应该打印:
My Message
Actor 的状态管理
Actor 也可以具有状态。在这种情况下,状态管理器将使用状态序列化器对对象进行序列化和反序列化,并对应用透明地处理这些操作。
public Task SayAsync(string message)
{
// 从键读取状态
var previousMessage = await this.StateManager.GetStateAsync<string>("lastmessage");
// 在序列化后为键设置新状态
await this.StateManager.SetStateAsync("lastmessage", message);
return previousMessage;
}
public String actorMethod(String message) {
// 从键读取状态并反序列化为 String
String previousMessage = super.getActorStateManager().get("lastmessage", String.class).block();
// 在序列化后为键设置新状态
super.getActorStateManager().set("lastmessage", message).block();
return previousMessage;
}
默认序列化器
Dapr 的默认序列化器是一个 JSON 序列化器,具有以下预期:
- 使用基本 JSON 数据类型以实现跨语言和跨平台兼容性:string、number、array、boolean、null 和另一个 JSON 对象。应用可序列化对象中的每个复杂属性类型(DateTime,例如),都应表示为 JSON 的基本类型之一。
- 使用默认序列化器持久化的数据也应保存为 JSON 对象,无需额外的引号或编码。下面的示例展示了字符串和 JSON 对象在 Redis 存储中的样子。
redis-cli MGET "ActorStateIT_StatefulActorService||StatefulActorTest||1581130928192||message
"This is a message to be saved and retrieved."
redis-cli MGET "ActorStateIT_StatefulActorService||StatefulActorTest||1581130928192||mydata
{"value":"My data value."}
- 自定义序列化器必须将对象序列化为
byte[]。 - 自定义序列化器必须将
byte[]反序列化为对象。 - 当用户提供自定义序列化器时,应将其作为
byte[]传输或持久化。持久化时,还要编码为 Base64 字符串。大多数 JSON 库原生支持此操作。
redis-cli MGET "ActorStateIT_StatefulActorService||StatefulActorTest||1581130928192||message
"VGhpcyBpcyBhIG1lc3NhZ2UgdG8gYmUgc2F2ZWQgYW5kIHJldHJpZXZlZC4="
redis-cli MGET "ActorStateIT_StatefulActorService||StatefulActorTest||1581130928192||mydata
"eyJ2YWx1ZSI6Ik15IGRhdGEgdmFsdWUuIn0="