使用 Dapr .NET SDK 开发应用程序
了解 .NET Dapr 应用程序的本地开发集成选项
同时管理多个任务
通常情况下,使用您喜欢的 IDE 或编辑器启动应用程序时,您只需运行一个任务:您正在调试的应用程序。然而,开发微服务要求您在本地开发过程中同时管理多个任务。一个微服务应用程序包含多个服务,您可能需要同时运行这些服务,并管理依赖项(如状态存储)。
将 Dapr 集成到您的开发过程中意味着您需要管理以下事项:
- 您想要运行的每个服务
- 每个服务的 Dapr sidecar
- Dapr 组件和配置清单
- 额外的依赖项,如状态存储
- 可选:用于 actor 的 Dapr placement 服务
本文档假设您正在构建一个生产应用程序,并希望创建一套可重复且稳健的开发实践。这里的指导是通用的,适用于任何使用 Dapr 的 .NET 服务器应用程序(包括 actor)。
组件管理
您有两种主要方法来存储 Dapr 本地开发的组件定义:
- 使用默认位置 (
~/.dapr/components
) - 使用您自定义的位置
在您的源代码库中创建一个文件夹来存储组件和配置,这样可以方便地对这些定义进行版本控制和共享。本文假设您在应用程序源代码旁边创建了一个文件夹来存储这些文件。
开发选项
选择以下链接之一以了解您可以在本地开发场景中使用的工具。这些文章按投入程度从低到高排序。您可能希望阅读所有文章以全面了解可用选项。
1 - 使用 Dapr CLI 进行 Dapr .NET SDK 开发
了解如何使用 Dapr CLI 进行本地开发
Dapr CLI
可以将其视为 .NET 伴侣指南:使用 Docker 的 Dapr 自托管指南的补充。
Dapr CLI 通过初始化本地的 Redis 容器、Zipkin 容器、placement 服务和 Redis 的组件清单,为您提供了一个良好的基础环境。这使您能够在全新安装且无需额外设置的情况下使用以下功能模块:
您可以使用 dapr run
命令来运行 .NET 服务,作为本地开发的一种策略。为每个服务运行此命令以启动您的应用程序。
- 优势: 由于这是 Dapr 默认安装的一部分,因此设置简单
- 劣势: 这会在您的机器上运行长时间的 Docker 容器,可能不太理想
- 劣势: 这种方法的可扩展性较差,因为需要为每个服务运行一个单独的命令
使用 Dapr CLI
对于每个服务,您需要选择:
- 用于寻址的唯一应用 ID (
app-id
) - 用于 HTTP 的唯一监听端口 (
port
)
您还应该决定存储组件的位置 (components-path
)。
可以从多个终端运行以下命令以启动每个服务,并替换相应的值。
dapr run --app-id <app-id> --app-port <port> --components-path <components-path> -- dotnet run -p <project> --urls http://localhost:<port>
解释: 此命令使用 dapr run
启动每个服务及其附属进程。命令的前半部分(在 --
之前)将所需的配置传递给 Dapr CLI。命令的后半部分(在 --
之后)将所需的配置传递给 dotnet run
命令。
💡 端口
由于您需要为每个服务配置一个唯一的端口,您可以使用此命令将该端口值传递给 Dapr 和服务。--urls http://localhost:<port>
将配置 ASP.NET Core 以监听提供的端口上的流量。在命令行中配置比在代码中硬编码监听端口更灵活。如果您的任何服务不接受 HTTP 流量,请通过删除 --app-port
和 --urls
参数来修改上述命令。
下一步
如果您需要调试,请使用调试器的附加功能附加到其中一个正在运行的进程。
如果您想扩展这种方法,请考虑编写一个脚本来为您的整个应用程序自动化此过程。
2 - 使用 .NET Aspire 进行 Dapr .NET SDK 开发
了解如何使用 .NET Aspire 进行本地开发
.NET Aspire
.NET Aspire 是一款开发工具,旨在通过提供一个框架,简化外部软件与 .NET 应用程序的集成过程。该框架允许第三方服务轻松地与您的软件集成、监控和配置。
Aspire 通过与流行的 IDE(包括 Microsoft Visual Studio、Visual Studio Code、JetBrains Rider 等)深度集成,简化了本地开发。在启动调试器的同时,自动启动并配置对其他集成(包括 Dapr)的访问。
虽然 Aspire 也支持将应用程序部署到各种云平台(如 Microsoft Azure 和 Amazon AWS),但本指南不涉及部署相关内容。更多信息请参阅 Aspire 的文档 这里。
先决条件
通过 CLI 使用 .NET Aspire
我们将从创建一个全新的 .NET 应用程序开始。打开您喜欢的 CLI 并导航到您希望创建新 .NET 解决方案的目录。首先使用以下命令安装一个模板,该模板将创建一个空的 Aspire 应用程序:
dotnet new install Aspire.ProjectTemplates
安装完成后,继续在当前目录中创建一个空的 .NET Aspire 应用程序。-n
参数允许您指定输出解决方案的名称。如果省略,.NET CLI 将使用输出目录的名称,例如 C:\source\aspiredemo
将导致解决方案被命名为 aspiredemo
。本教程的其余部分将假设解决方案名为 aspiredemo
。
dotnet new aspire -n aspiredemo
这将在您的目录中创建两个 Aspire 特定的目录和一个文件:
aspiredemo.AppHost/
包含用于配置应用程序中使用的每个集成的 Aspire 编排项目。aspiredemo.ServiceDefaults/
包含一组扩展,旨在跨您的解决方案共享,以帮助提高 Aspire 提供的弹性、服务发现和遥测能力(这些与 Dapr 本身提供的功能不同)。aspiredemo.sln
是维护当前解决方案布局的文件
接下来,我们将创建一个项目,作为我们的 Dapr 应用程序。从同一目录中,使用以下命令创建一个名为 MyApp
的空 ASP.NET Core 项目。它将在 MyApp\MyApp.csproj
中相对于您的当前目录创建。
接下来,我们将配置 AppHost 项目以添加支持本地 Dapr 开发所需的包。使用以下命令导航到 AppHost 目录,并从 NuGet 安装 Aspire.Hosting.Dapr
包到项目中。我们还将添加对 MyApp
项目的引用,以便在注册过程中引用它。
cd aspiredemo.AppHost
dotnet add package Aspire.Hosting.Dapr
dotnet add reference ../MyApp/
接下来,我们需要将 Dapr 配置为与您的项目一起加载的资源。在您喜欢的 IDE 中打开该项目中的 Program.cs
文件。它应类似于以下内容:
var builder = DistributedApplication.CreateBuilder(args);
builder.Build().Run();
如果您熟悉 ASP.NET Core 项目中使用的依赖注入方法或其他使用 Microsoft.Extensions.DependencyInjection
功能的项目,您会发现这将是一个熟悉的体验。
因为我们已经添加了对 MyApp
的项目引用,我们需要在此配置中添加一个引用。在 builder.Build().Run()
行之前添加以下内容:
var myApp = builder
.AddProject<Projects.MyApp>("myapp")
.WithDaprSidecar();
因为项目引用已添加到此解决方案中,您的项目在此处显示为 Projects.
命名空间中的一个类型。您为项目分配的变量名称在本教程中并不重要,但如果您想在此项目和另一个项目之间创建引用以使用 Aspire 的服务发现功能,则会使用它。
添加 .WithDaprSidecar()
将 Dapr 配置为 .NET Aspire 资源,以便在项目运行时,sidecar 将与您的应用程序一起部署。这接受许多不同的选项,并可以选择性地配置,如以下示例所示:
DaprSidecarOptions sidecarOptions = new()
{
AppId = "my-other-app",
AppPort = 8080, //注意,如果您打算配置 pubsub、actor 或 workflow,从 Aspire v9.0 开始,此参数是必需的
DaprGrpcPort = 50001,
DaprHttpPort = 3500,
MetricsPort = 9090
};
builder
.AddProject<Projects.MyOtherApp>("myotherapp")
.WithReference(myApp)
.WithDaprSidecar(sidecarOptions);
如上例所示,从 .NET Aspire 9.0 开始,如果您打算使用 Dapr 需要调用到您的应用程序的任何功能,例如 pubsub、actor 或 workflow,您将需要指定您的 AppPort 作为配置选项,因为 Aspire 不会在运行时自动将其传递给 Dapr。预计这种行为将在未来的版本中更改,因为修复已合并并可以在
这里 跟踪。
当您在 IDE 中打开解决方案时,确保 aspiredemo.AppHost
被配置为您的启动项目,但当您在调试配置中启动它时,您会注意到您的集成控制台应反映您预期的 Dapr 日志,并且它将可用于您的应用程序。
3 - 使用 Project Tye 进行 Dapr .NET SDK 开发
了解如何使用 Project Tye 进行本地开发
Project Tye
.NET Project Tye 是一个专为简化运行多个 .NET 服务而设计的微服务开发工具。Tye 允许您将多个 .NET 服务、进程和容器镜像的配置整合为一个可运行的应用程序。
对于 .NET Dapr 开发者来说,Tye 的优势在于:
- Tye 可以自动化使用 dapr CLI
- Tye 遵循 .NET 的约定,对 .NET 服务几乎无需额外配置
- Tye 能够管理容器中依赖项的生命周期
优缺点:
- 优点: Tye 可以自动化上述所有步骤。您无需再担心端口或应用程序 ID 等细节。
- 优点: 由于 Tye 也可以管理容器,您可以将这些容器作为应用程序的一部分定义,并避免机器上长时间运行的容器。
使用 Tye
按照 Tye 入门指南 安装 tye
CLI,并为您的应用程序创建 tye.yaml
文件。
接下来,按照 Tye Dapr 配方 中的步骤添加 Dapr。确保在 tye.yaml
中使用 components-path
指定组件文件夹的相对路径。
然后,添加任何额外的容器依赖项,并将组件定义添加到您之前创建的文件夹中。
您应该得到如下内容:
name: store-application
extensions:
# Dapr 的配置在这里。
- name: dapr
components-path: <components-path>
# 要运行的服务在这里。
services:
# 名称将用作应用程序 ID。对于 .NET 项目,Tye 只需要项目文件的路径。
- name: orders
project: orders/orders.csproj
- name: products
project: products/products.csproj
- name: store
project: store/store.csproj
# 您想要运行的容器需要一个镜像名称和一组要暴露的端口。
- name: redis
image: redis
bindings:
- port: 6973
将 tye.yaml
和应用程序代码一起提交到源代码管理中。
您现在可以使用 tye run
从一个终端启动整个应用程序。运行时,Tye 在 http://localhost:8000
提供一个仪表板以查看应用程序状态和日志。
下一步
Tye 会将您的服务作为标准 .NET 进程在本地运行。如果您需要调试,可以使用调试器附加到正在运行的进程之一。由于 Tye 了解 .NET,它可以在启动时暂停进程以便进行调试。
如果您希望在容器中进行本地测试,Tye 还提供了一个选项,可以在容器中运行您的服务。
4 - 使用 Docker-Compose 进行 Dapr .NET SDK 开发
了解如何使用 Docker-Compose 进行本地开发
Docker-Compose
这可以看作是 .NET 伴侣指南:使用 Docker 的 Dapr 自托管指南 的补充。
docker-compose
是 Docker Desktop 附带的一个命令行工具,您可以用它同时运行多个容器。它提供了一种自动化管理多个容器生命周期的方法,为面向 Kubernetes 的应用程序提供类似于生产环境的开发体验。
- 优势在于:
docker-compose
帮助您管理容器,您可以将依赖项作为应用程序的一部分进行定义,并停止机器上长时间运行的容器。 - 劣势在于: 需要较多的前期投入,服务需要先容器化。
- 劣势在于: 如果您不熟悉 Docker,可能会遇到调试和故障排除的困难。
使用 docker-compose
从 .NET 的角度来看,使用 Dapr 的 docker-compose
并不需要特别的指导。docker-compose
负责运行容器,一旦您的服务在容器中,配置它就和其他编程技术类似。
💡 应用端口
在容器中,ASP.NET Core 应用程序默认监听 80 端口。请记住这一点,以便在配置 --app-port
时使用。总结这种方法:
- 为每个服务创建一个
Dockerfile
- 创建一个
docker-compose.yaml
并将其提交到源代码库
要了解如何编写 docker-compose.yaml
,您可以从 Hello, docker-compose 示例 开始。
类似于使用 dapr run
本地运行,对于每个服务,您需要选择一个唯一的 app-id。选择容器名称作为 app-id 可以帮助您更容易记住。
compose 文件至少应包含以下内容:
- 容器之间通信所需的网络
- 每个服务的容器
- 一个
<service>-daprd
sidecar 容器,指定服务的端口和 app-id - 在容器中运行的其他依赖项(例如 redis)
- 可选:Dapr placement 容器(用于 actor)
您还可以查看 eShopOnContainers 示例应用程序中的更大示例。