将 Azure Functions 与 .NET Aspire 配合使用(预览版)

.NET Aspire 是一个有观点的堆栈,可简化云中分布式应用程序的开发。 通过 .NET Aspire 与 Azure Functions 的集成,可以将 Azure Functions .NET 项目作为 .NET Aspire 应用主机的一部分进行开发、调试和协调。

重要

.NET Aspire 与 Azure Functions 的集成目前以预览版提供,可能会更改。

先决条件

设置用于将 Azure Functions 与 .NET Aspire 配合使用的开发环境:

  • 安装 .NET 9 SDK.NET Aspire 9.0 或更高版本。 尽管需要 .NET 9 SDK,但 .NET Aspire 9.0 支持 .NET 8 和 .NET 9 框架。
  • 如果你使用的是 Visual Studio,请将其更新到 17.12 版本或更高版本。 还必须具有最新版本的适用于 Visual Studio 的 Azure Functions 工具。 检查更新:
    1. 转到“工具”“选项” 。
    2. “项目和解决方案”下,选择 “Azure Functions”。
    3. 选择“检查更新”并按提示安装更新。

解决方案结构

使用 Azure Functions 和 .NET Aspire 的解决方案具有多个项目,包括 应用主机项目 和一个或多个 Functions 项目。

应用主机项目是应用程序的入口点。 它协调应用程序的组件(包括 Functions 项目)的设置。

解决方案通常还包括 服务默认 项目。 此项目提供一组默认服务和配置,用于应用程序中的项目。

应用托管项目

若要成功配置集成,请确保应用主机项目满足以下要求:

  • 应用主机项目必须引用 Aspire.Hosting.Azure.Functions。 此包定义集成所需的逻辑。
  • 对于你希望包含在业务流程中的每个 Functions 项目,应用主机项目都需要有一个项目引用。
  • 在应用主机的 Program.cs 文件中,必须通过调用 IDistributedApplicationBuilder 实例上的 AddAzureFunctionsProject<TProject>() 来包含项目。 使用此方法,而不是使用 AddProject<TProject>() 方法,正如您在 .NET Aspire 中为其他项目类型所做的那样。 如果使用 AddProject<TProject>(),Functions 项目无法正确启动。

以下示例演示应用主机项目的最小 Program.cs 文件:

var builder = DistributedApplication.CreateBuilder(args);

builder.AddAzureFunctionsProject<Projects.MyFunctionsProject>("MyFunctionsProject");

builder.Build().Run();

Azure Functions 项目

若要成功配置集成,请确保 Azure Functions 项目满足以下要求:

以下示例演示 .NET Aspire 中使用的 Functions 项目的最小 Program.cs 文件:

using Microsoft.Azure.Functions.Worker.Builder;
using Microsoft.Extensions.Hosting;

var builder = FunctionsApplication.CreateBuilder(args);

builder.AddServiceDefaults();

builder.ConfigureFunctionsWebApplication();

builder.Build().Run();

此示例不包括出现在许多其他 Program.cs 示例和 Azure Functions 模板中的默认 Application Insights 配置。 而是通过调用该方法 builder.AddServiceDefaults 在 .NET Aspire 中配置 OpenTelemetry 集成。

若要充分利用集成,请考虑以下准则:

  • 不要在 Functions 项目中包括任何直接的 Application Insights 集成。 而 .NET Aspire 中的监视通过 OpenTelemetry 支持进行处理。 可以将 .NET Aspire 配置为通过服务默认项目将数据导出到 Azure Monitor。
  • 不要在 local.settings.json Functions 项目的文件中定义自定义应用设置。 应位于 local.settings.json 中的唯一设置是 "FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated"。 通过应用主机项目设置所有其他应用配置。

使用 .NET Aspire 的连接配置

应用主机项目定义资源,并帮助你使用代码在它们之间创建连接。 本部分介绍如何配置和自定义 Azure Functions 项目使用的连接。

.NET Aspire 包括有助于入门的默认连接权限。 但是,这些权限可能不适合或足以满足应用程序要求。

对于使用 Azure 基于角色的访问控制(RBAC)的方案,可以通过对项目资源调用 WithRoleAssignments() 方法来自定义权限。 调用 WithRoleAssignments()时,将删除所有默认角色分配,并且必须显式定义所需的完整角色分配。 如果您的应用程序托管在 Azure 容器应用中,使用WithRoleAssignments()时还需要在DistributedApplicationBuilder上调用AddAzureContainerAppEnvironment()

Azure Functions 主机存储

Azure Functions 需要主机存储连接 (AzureWebJobsStorage) 才能实现其多个核心行为。 在应用主机项目中调用 AddAzureFunctionsProject<TProject>() 时,默认情况下会创建一个 AzureWebJobsStorage 连接,并提供给 Functions 项目。 此默认连接使用 Azure 存储模拟器进行本地开发运行,并在部署存储帐户时自动预配存储帐户。 若要获得更多控制,可以通过调用 .WithHostStorage() Functions 项目资源来替换此连接。

.NET Aspire 为主机存储连接设置的默认权限取决于你是否调用 WithHostStorage() 。 添加 WithHostStorage() 会删除存储帐户参与者分配。 下表列出了 .NET Aspire 为主机存储连接设置的默认权限:

主机存储连接 默认角色
不调用 WithHostStorage() 存储 Blob 数据参与者
存储队列数据参与者
存储表数据参与者
存储帐户贡献者
调用 WithHostStorage() 存储 Blob 数据参与者
存储队列数据参与者
存储表数据参与者

以下示例显示了用于替换主机存储并指定角色分配的应用主机项目的最小 Program.cs 文件:

using Azure.Provisioning.Storage;

var builder = DistributedApplication.CreateBuilder(args);

builder.AddAzureContainerAppEnvironment("myEnv");

var myHostStorage = builder.AddAzureStorage("myHostStorage");

builder.AddAzureFunctionsProject<Projects.MyFunctionsProject>("MyFunctionsProject")
    .WithHostStorage(myHostStorage)
    .WithRoleAssignments(myHostStorage, StorageBuiltInRole.StorageBlobDataOwner);

builder.Build().Run();

注释

存储 Blob 数据所有者”是我们针对主机存储连接的基本需求推荐的角色。 如果与 Blob 服务的连接仅具有“存储 Blob 数据参与者”的 .NET Aspire 默认设置,则应用可能会遇到问题。

对于生产场景,请包括对 WithHostStorage()WithRoleAssignments() 的调用。 然后,可以显式设置此角色,同时设置所需的任何其他角色。

触发器和绑定连接

触发器和绑定按名称引用连接。 以下 .NET Aspire 集成通过调用项目资源中的 WithReference() 提供这些连接:

.NET Aspire 集成 默认角色
Azure Blob 存储服务 存储 Blob 数据参与者
存储队列数据参与者
存储表数据参与者
Azure 队列存储 存储 Blob 数据参与者
存储队列数据参与者
存储表数据参与者
Azure 事件中心 Azure 事件中心数据所有者
Azure 服务总线 Azure 服务总线数据所有者

以下示例展示了一个用于应用主机项目的最小 Program.cs 文件,该项目配置了一个队列触发器。 在此示例中,相应的队列触发器的 Connection 属性设置为 MyQueueTriggerConnection,因此调用时指定了 WithReference() 的名称。

var builder = DistributedApplication.CreateBuilder(args);

var myAppStorage = builder.AddAzureStorage("myAppStorage").RunAsEmulator();
var queues = myAppStorage.AddQueues("queues");

builder.AddAzureFunctionsProject<Projects.MyFunctionsProject>("MyFunctionsProject")
    .WithReference(queues, "MyQueueTriggerConnection");

builder.Build().Run();

对于其他集成,调用 WithReference 以不同的方式设置配置。 这些配置可用于.NET Aspire 客户端集成,但不可用于触发和绑定。 对于这些集成,调用 WithEnvironment() 传递触发器或绑定的连接信息以进行解析。

以下示例演示如何为公开连接字符串表达式的资源设置环境变量 MyBindingConnection

builder.AddAzureFunctionsProject<Projects.MyFunctionsProject>("MyFunctionsProject")
    .WithEnvironment("MyBindingConnection", otherIntegration.Resource.ConnectionStringExpression);

如果希望 .NET Aspire 客户端集成和触发器和绑定系统都使用连接,则可以同时配置 WithReference()WithEnvironment()

对于某些资源,在本地运行和发布到 Azure 时的连接结构可能会有所不同。 在之前的示例中,otherIntegration 可以是作为模拟器运行的资源,因此 ConnectionStringExpression 将返回模拟器连接字符串。 但是,发布资源时,.NET Aspire 可能会设置基于标识的连接,并 ConnectionStringExpression 返回服务的 URI。 在这种情况下,若要 为 Azure Functions 设置基于标识的连接,可能需要提供不同的环境变量名称。

以下示例使用 builder.ExecutionContext.IsPublishMode 以有条件地添加必要的后缀:

builder.AddAzureFunctionsProject<Projects.MyFunctionsProject>("MyFunctionsProject")
    .WithEnvironment("MyBindingConnection" + (builder.ExecutionContext.IsPublishMode ? "__serviceUri" : ""), otherIntegration.Resource.ConnectionStringExpression);

有关每个绑定支持的连接格式以及这些格式所需的权限的详细信息,请参阅绑定的 参考页

托管应用程序

默认情况下,将 Azure Functions 项目发布到 Azure 时,它将部署到 Azure 容器应用。

在预览期间,容器应用资源不支持事件驱动的缩放。 Azure Functions 支持不适用于在此模式下部署的应用。 如果需要开具支持票证,请选择 Azure 容器应用资源类型。

注意事项和最佳做法

评估 Azure Functions 与 .NET Aspire 的集成时,请考虑以下几点:

  • 对集成的支持目前为预览版。

  • 通过 .NET Aspire 的触发器和绑定配置目前仅限于特定的集成。 有关详细信息,请参阅本文中的 .NET Aspire 连接配置

  • Program.cs 文件应使用 IHostApplicationBuilder 版本的主机实例启动IHostApplicationBuilder 允许调用 builder.AddServiceDefaults() 以将 .NET Aspire 服务默认值 添加到 Functions 项目。

  • .NET Aspire 使用 OpenTelemetry 进行监视。 可以将 .NET Aspire 配置为通过服务默认项目将数据导出到 Azure Monitor。

    在许多其他 Azure Functions 上下文中,你可以通过注册辅助角色服务来包含与 Application Insights 的直接集成。 不建议在 .NET Aspire 中集成此类。 这可能会导致Microsoft.ApplicationInsights.WorkerService 在版本 2.22.0 下发生运行时错误,但版本 2.23.0 解决了此问题。 使用 .NET Aspire 时,请从 Functions 项目中删除任何直接 Application Insights 集成。

  • 对于登记到 .NET Aspire 业务流程中的 Functions 项目,大多数应用程序配置应来自 .NET Aspire 应用主机项目。 避免在 local.settings.json 中设置除 FUNCTIONS_WORKER_RUNTIME 设置之外的任何内容。 如果在 .NET Aspire 中 local.settings.json 设置相同的环境变量,则系统会使用 .NET Aspire 版本。

  • 不要为任何 local.settings.json连接配置 Azure 存储模拟器。 许多 Functions 起始模板将模拟器作为 AzureWebJobsStorage 的默认选项。 然而,模拟器的配置可能会导致某些开发工具启动一个与 .NET Aspire 使用的版本相冲突的模拟器版本。