.NET Aspire Azure PostgreSQL Entity Framework Core 集成

包含:托管集成已包含 - Client 集成已包含Client 集成

Azure 数据库 for PostgreSQL(灵活 Server)是基于开源 Postgres 数据库引擎的关系数据库服务。 它是一种完全托管的数据库即服务,可以处理具有可预测性能、安全性、高可用性和动态可伸缩性的任务关键型工作负荷。 .NET Aspire Azure PostgreSQL 集成提供了一种连接到现有 AzurePostgreSQL 数据库的方法,或者使用 .NET从 docker.io/library/postgres 创建新实例。

托管集成

托管集成 .NET AspireAzurePostgreSQL 将 PostgreSQL 灵活服务器和数据库建模为 AzurePostgresFlexibleServerResourceAzurePostgresFlexibleServerDatabaseResource 类型。 托管集成中固有可用的其他类型的表示在以下资源中:

若要在 应用主机 项目中将这些类型和 API 表示为资源,请安装 📦Aspire.Hosting.Azure.PostgreSQL NuGet 包:

dotnet add package Aspire.Hosting.Azure.PostgreSQL

有关详细信息,请查看 dotnet add package

托管集成AzurePostgreSQL 依赖于 📦Aspire.Hosting.PostgreSQL NuGet 包,并将其扩展以支持 Azure。 你可以使用 .NET AspirePostgreSQL 集成.NET AspirePostgreSQLEntity Framework Core 集成 所能做的所有事情,也可以在此集成中完成。

添加 AzurePostgreSQL 服务器资源

安装 .NET AspireAzurePostgreSQL 托管集成后,请在应用主机项目中调用 AddAzurePostgresFlexibleServer 扩展方法:

var builder = DistributedApplication.CreateBuilder(args);

var postgres = builder.AddAzurePostgresFlexibleServer("postgres");
var postgresdb = postgres.AddDatabase("postgresdb");

var exampleProject = builder.AddProject<Projects.ExampleProject>()
                            .WithReference(postgresdb);

上述对 AddAzurePostgresFlexibleServer 的调用将 PostgreSQL 服务器资源配置为 AzurePostgres 的灵活 Server

重要

默认情况下,AddAzurePostgresFlexibleServer 配置 Microsoft Entra ID 身份验证。 这需要更改需要连接到这些资源的应用程序。 有关详细信息,请参阅 Client 整合

提示

调用 AddAzurePostgresFlexibleServer时,它会隐式调用 AddAzureProvisioning,这增加了在应用启动期间动态生成 Azure 资源的支持。 应用必须配置相应的订阅和位置。 有关详细信息,请参阅 本地预配:配置

预配生成的 Bicep

如果你不熟悉 Bicep,它是一种领域专用语言,用于定义 Azure 资源。 使用 .NET.NET Aspire时,无需手动编写 Bicep,因为预配 API 会为你生成 Bicep。 发布应用时,生成的 Bicep 文件将与清单文件一同输出。 添加 AzurePostgreSQL 资源时,会生成以下 Bicep 代码段:

@description('The ___location for the resource(s) to be deployed.')
param ___location string = resourceGroup().___location

resource postgres_flexible 'Microsoft.DBforPostgreSQL/flexibleServers@2024-08-01' = {
  name: take('postgresflexible-${uniqueString(resourceGroup().id)}', 63)
  ___location: ___location
  properties: {
    authConfig: {
      activeDirectoryAuth: 'Enabled'
      passwordAuth: 'Disabled'
    }
    availabilityZone: '1'
    backup: {
      backupRetentionDays: 7
      geoRedundantBackup: 'Disabled'
    }
    highAvailability: {
      mode: 'Disabled'
    }
    storage: {
      storageSizeGB: 32
    }
    version: '16'
  }
  sku: {
    name: 'Standard_B1ms'
    tier: 'Burstable'
  }
  tags: {
    'aspire-resource-name': 'postgres-flexible'
  }
}

resource postgreSqlFirewallRule_AllowAllAzureIps 'Microsoft.DBforPostgreSQL/flexibleServers/firewallRules@2024-08-01' = {
  name: 'AllowAllAzureIps'
  properties: {
    endIpAddress: '0.0.0.0'
    startIpAddress: '0.0.0.0'
  }
  parent: postgres_flexible
}

output connectionString string = 'Host=${postgres_flexible.properties.fullyQualifiedDomainName}'

output name string = postgres_flexible.name

前面的 Bicep 是预配灵活服务器资源的模块 AzurePostgreSQL 。 此外,在单独的模块中为 Azure 资源创建角色分配:

@description('The ___location for the resource(s) to be deployed.')
param ___location string = resourceGroup().___location

param postgres_flexible_outputs_name string

param principalType string

param principalId string

param principalName string

resource postgres_flexible 'Microsoft.DBforPostgreSQL/flexibleServers@2024-08-01' existing = {
  name: postgres_flexible_outputs_name
}

resource postgres_flexible_admin 'Microsoft.DBforPostgreSQL/flexibleServers/administrators@2024-08-01' = {
  name: principalId
  properties: {
    principalName: principalName
    principalType: principalType
  }
  parent: postgres_flexible
}

除了 PostgreSQL 灵活服务器,它还预配 Azure 防火墙规则以允许所有 Azure IP 地址。 最后,将为 PostgreSQL 服务器创建管理员,连接字符串将输出为输出变量。 生成的 Bicep 作为起点,受 C# 中资源配置基础设施更改的影响。 直接对 Bicep 文件的自定义项所做的更改将被覆盖,因此请通过 C# 预配 API 进行更改,以确保它们反映在生成的文件中。

自定义预配基础结构

所有 .NET AspireAzure 资源都是 AzureProvisioningResource 类型的子类。 此类型通过提供一个流畅的 API,使用 Azure API 对 ConfigureInfrastructure<T>(IResourceBuilder<T>, Action<AzureResourceInfrastructure>) 资源进行配置,从而实现对生成的 Bicep 的自定义。 例如,可以配置 kindconsistencyPolicylocations等。 以下示例演示如何自定义 PostgreSQL 服务器资源:

builder.AddAzurePostgresFlexibleServer("postgres")
    .ConfigureInfrastructure(infra =>
    {
        var flexibleServer = infra.GetProvisionableResources()
                                  .OfType<PostgreSqlFlexibleServer>()
                                  .Single();

        flexibleServer.Sku = new PostgreSqlFlexibleServerSku
        {
            Tier = PostgreSqlFlexibleServerSkuTier.Burstable,
        };
        flexibleServer.HighAvailability = new PostgreSqlFlexibleServerHighAvailability
        {
            Mode = PostgreSqlFlexibleServerHighAvailabilityMode.ZoneRedundant,
            StandbyAvailabilityZone = "2",
        };
        flexibleServer.Tags.Add("ExampleKey", "Example value");
    });

前面的代码:

还有更多配置选项可用于自定义 PostgreSQL 灵活服务器资源。 有关详细信息,请参阅 Azure.Provisioning.PostgreSqlAzure。预配自定义

连接到现有 AzurePostgreSQL 灵活服务器

你可能已有一个现有的灵活服务器 AzurePostgreSQL 并希望连接到它。 可以向应用主机添加连接字符串,而无需表示新的 AzurePostgreSQL 灵活服务器资源。 若要将连接添加到现有 AzurePostgreSQL 灵活服务器,请调用 AddConnectionString 方法:

var builder = DistributedApplication.CreateBuilder(args);

var postgres = builder.AddConnectionString("postgres");

builder.AddProject<Projects.WebApplication>("web")
       .WithReference(postgres);

// After adding all resources, run the app...

注意

连接字符串用于表示各种连接信息,包括数据库连接、消息代理、终结点 URI 和其他服务。 在 .NET.NET Aspire 名词中,术语“连接字符串”用于表示任何类型的连接信息。

连接字符串是在应用主机的配置中配置的,通常在 部分下的 ConnectionStrings下。 应用主机将此连接字符串作为环境变量注入到所有依赖资源中,例如:

{
    "ConnectionStrings": {
        "postgres": "Server=<PostgreSQL-server-name>.postgres.database.azure.com;Database=<database-name>;Port=5432;Ssl Mode=Require;User Id=<username>;"
    }
}

依赖资源可以通过调用 GetConnectionString 方法并传递连接名称作为参数来访问注入的连接字符串,在本例中为 "postgres"GetConnectionString API 是 IConfiguration.GetSection("ConnectionStrings")[name]的简称。

以容器身份运行 AzurePostgreSQL 资源

托管集成 AzurePostgreSQL 支持将 PostgreSQL 服务器作为本地容器运行。 这适用于想要在本地运行 PostgreSQL 服务器以进行开发和测试的情况,避免需要预配 Azure 资源或连接到现有 AzurePostgreSQL 服务器。

若要将 PostgreSQL 服务器作为容器运行,请调用 RunAsContainer 方法:

var builder = DistributedApplication.CreateBuilder(args);

var postgres = builder.AddAzurePostgresFlexibleServer("postgres")
                      .RunAsContainer();

var postgresdb = postgres.AddDatabase("postgresdb");

var exampleProject = builder.AddProject<Projects.ExampleProject>()
                            .WithReference(postgresdb);

前面的代码将 AzurePostgreSQL 灵活 Server 资源配置为在容器中本地运行。

提示

RunAsContainer 方法可用于本地开发和测试。 API 提供一个可选委托,允许您自定义底层的 PostgresServerResource 配置。 例如,您可以添加 pgAdmin 和 pgWeb,增加数据卷或数据绑定挂载,还可以增加初始化绑定挂载。 有关详细信息,请参阅 .NET AspirePostgreSQL 托管集成 部分。

将 AzurePostgreSQL 服务器配置为使用密码身份验证

默认情况下,AzurePostgreSQL 服务器配置为使用 Microsoft Entra ID 身份验证。 如果要使用密码身份验证,可以通过调用 WithPasswordAuthentication 方法将服务器配置为使用密码身份验证:

var builder = DistributedApplication.CreateBuilder(args);

var username = builder.AddParameter("username", secret: true);
var password = builder.AddParameter("password", secret: true);

var postgres = builder.AddAzurePostgresFlexibleServer("postgres")
                      .WithPasswordAuthentication(username, password);

var postgresdb = postgres.AddDatabase("postgresdb");

var exampleProject = builder.AddProject<Projects.ExampleProject>()
                            .WithReference(postgresdb);

前面的代码将 AzurePostgreSQL 服务器配置为使用密码身份验证。 usernamepassword 参数作为参数添加到应用主机,调用 WithPasswordAuthentication 方法以配置 AzurePostgreSQL 服务器以使用密码身份验证。 有关详细信息,请参阅 外部参数

Client 集成

若要开始使用 .NET AspirePostgreSQLEntity Framework Core 客户端集成,请安装 📦Aspire..AzureNpgsql.EntityFrameworkCore。PostgreSQL 客户端使用项目中的 NuGet 包,即使用 PostgreSQL 客户端的应用程序的项目。 .NET Aspire PostgreSQL Entity Framework Core 客户端集成注册您所需的 DbContext 子类实例,可用于与 PostgreSQL进行交互。

dotnet add package Aspire.Azure.Npgsql.EntityFrameworkCore.PostgreSQL

可以通过使用客户端集成来消耗PostgreSQL连接,方法是调用AddAzureNpgsqlDataSource

builder.AddAzureNpgsqlDbContext<YourDbContext>(connectionName: "postgresdb");

提示

connectionName 参数必须与在应用主机项目中添加 PostgreSQL 服务器资源时使用的名称匹配。

前面的代码片段演示了如何使用AddAzureNpgsqlDbContext方法来注册一个YourDbContext实例,该实例使用身份验证(Azure)并具有(已共用以提高性能)的特点。 此 "postgresdb" 连接名称对应于连接字符串配置值。

YourDbContext 添加到生成器后,可以使用依赖项注入获取 YourDbContext 实例。 例如,若要从示例服务中检索数据源对象,请将其定义为构造函数参数,并确保 ExampleService 类注册到依赖项注入容器:

public class ExampleService(YourDbContext context)
{
    // Use context...
}

有关依赖项注入的详细信息,请参阅 .NET 依赖项注入

扩充 Npgsql 数据库上下文

你可能更喜欢使用标准 Entity Framework 方法获取数据库上下文并将其添加到依赖项注入容器:

builder.Services.AddDbContext<YourDbContext>(options =>
    options.UseNpgsql(builder.Configuration.GetConnectionString("postgresdb")
        ?? throw new InvalidOperationException("Connection string 'postgresdb' not found.")));

注意

传递给 GetConnectionString 方法的连接字符串名称必须与在应用主机项目中添加 PostgreSQL 服务器资源时使用的名称匹配。 有关详细信息,请参阅 添加 PostgreSQL 服务器资源

以这种方式创建数据库上下文时具有更大的灵活性,例如:

  • 可以重复使用数据库上下文的现有配置代码,而无需为 .NET.NET Aspire重写它。
  • 可以使用 Entity Framework Core 拦截器来修改数据库操作。
  • 可以选择不使用 Entity Framework Core 上下文池,在某些情况下性能可能更好。

如果使用此方法,通过调用 .NET 方法,可以为数据库上下文添加 .NET AspireEnrichAzureNpgsqlDbContext 样式的重试、运行状况检查、日志记录和遥测功能。

builder.EnrichAzureNpgsqlDbContext<YourDbContext>(
    configureSettings: settings =>
    {
        settings.DisableRetry = false;
        settings.CommandTimeout = 30;
    });

settings 参数是 AzureNpgsqlEntityFrameworkCorePostgreSQLSettings 类的实例。

可能还需要配置 Npgsql 的特定选项,或者以其他方式注册 DbContext 。 在这种情况下,通过调用 EnrichAzureNpgsqlDbContext 扩展方法执行此作,如以下示例所示:

var connectionString = builder.Configuration.GetConnectionString("postgresdb");

builder.Services.AddDbContextPool<YourDbContext>(
    dbContextOptionsBuilder => dbContextOptionsBuilder.UseNpgsql(connectionString));

builder.EnrichAzureNpgsqlDbContext<YourDbContext>();

配置

.NET Aspire Azure PostgreSQL EntityFrameworkCore Npgsql 集成提供了多个选项,用于根据项目的要求和约定配置数据库连接。

使用连接字符串

使用配置节中 ConnectionStrings 定义的连接字符串时,在调用 AddAzureNpgsqlDataSource时提供连接字符串的名称:

builder.AddAzureNpgsqlDbContext<YourDbContext>("postgresdb");

可以从 ConnectionStrings 配置部分中检索连接字符串。例如,考虑以下 JSON 配置:

{
  "ConnectionStrings": {
    "postgresdb": "Host=myserver;Database=test"
  }
}

有关如何配置连接字符串的详细信息,请参阅 Npgsql 连接字符串文档

注意

用户名和密码会自动从设置中提供的凭据推断。

使用配置提供器

.NET Aspire Azure PostgreSQLEntityFrameworkCore Npgsql 集成支持 Microsoft.Extensions.Configuration。 它使用AzureNpgsqlEntityFrameworkCorePostgreSQLSettings密钥从配置中加载Aspire:Npgsql:EntityFrameworkCore:PostgreSQL。 例如,请考虑以下 appsettings.json 文件,该文件配置了一些可用选项:

{
  "Aspire": {
    "Npgsql": {
      "EntityFrameworkCore": {
        "PostgreSQL": {
          "DisableHealthChecks": true,
          "DisableTracing": true
        }
      }
    }
  }
}
使用内联委托

可以在代码中配置设置,通过传递 Action<AzureNpgsqlEntityFrameworkCorePostgreSQLSettings> configureSettings 委托来直接在代码中设置某些或所有选项,例如,从代码中禁用健康检查:

builder.AddAzureNpgsqlDbContext<YourDbContext>(
    "postgresdb",
    settings => settings.DisableHealthChecks = true);

或者,可以使用 EnrichAzureNpgsqlDbContext 扩展方法配置设置:

builder.EnrichAzureNpgsqlDbContext<YourDbContext>(
    settings => settings.DisableHealthChecks = true);

使用 AzureNpgsqlEntityFrameworkCorePostgreSQLSettings.Credential 属性建立连接。 如果未配置凭据,则使用 DefaultAzureCredential

当连接字符串包含用户名和密码时,将忽略凭据。

故障排除

在极少数情况下,如果未提供Username属性,并且集成无法使用应用程序的托管标识来检测它,Npgsql 会引发异常,其消息如下所示:

Npgsql.PostgresException (0x80004005): 28P01:用户密码身份验证失败...

在这种情况下,可以在连接字符串中配置 Username 属性并使用 EnrichAzureNpgsqlDbContext,通过 UseNpgsql 传递连接字符串。

builder.Services.AddDbContextPool<YourDbContext>(
    options => options.UseNpgsql(newConnectionString));

builder.EnrichAzureNpgsqlDbContext<YourDbContext>();

配置多个 DbContext 类

如果要注册多个具有不同配置的 DbContext,可以使用配置节名称为 $"Aspire:Npgsql:EntityFrameworkCore:PostgreSQL:{typeof(TContext).Name}"。 json 配置如下所示:

{
  "Aspire": {
    "Npgsql": {
      "EntityFrameworkCore": {
        "PostgreSQL": {
          "ConnectionString": "<YOUR CONNECTION STRING>",
          "DisableHealthChecks": true,
          "DisableTracing": true,
          "AnotherDbContext": {
            "ConnectionString": "<ANOTHER CONNECTION STRING>",
            "DisableTracing": false
          }
        }
      }
    }
  }
}

然后,使用 AddNpgsqlDbContext 类型参数调用 AnotherDbContext 方法将从 Aspire:Npgsql:EntityFrameworkCore:PostgreSQL:AnotherDbContext 节加载设置。

builder.AddAzureNpgsqlDbContext<AnotherDbContext>();

Client 整合健康检查

默认情况下,.NET.NET Aspire客户端集成 对所有服务启用了 健康检查。 同样,许多 .NET.NET Aspire托管集成 也启用健康检查端点。 有关详细信息,请参阅:

默认情况下,.NET AspirePostgreSQLEntity Framework Core 集成处理以下内容:

  • 添加了DbContextHealthCheck,它调用了EF Core的CanConnectAsync方法。 健康检查的名称是 TContext 类型的名称。
  • /health HTTP 终结点集成,该终结点指定所有已注册的运行状况检查都必须通过,才能使应用被视为已经准备好接受流量。

可观测性和遥测

.NET .NET Aspire 集成会自动设置日志记录、跟踪和指标配置,这些配置有时称为 可观测性的支柱。 有关集成可观测性和遥测的详细信息,请参阅 .NET.NET Aspire 集成概述。 根据支持服务,某些集成可能仅支持其中一些功能。 例如,某些集成支持日志记录和跟踪,但不支持指标。 也可以使用 配置 部分中介绍的技术禁用遥测功能。

伐木

.NET Aspire PostgreSQL Entity Framework Core 集成使用以下日志类别:

  • Microsoft.EntityFrameworkCore.ChangeTracking
  • Microsoft.EntityFrameworkCore.Database.Command
  • Microsoft.EntityFrameworkCore.Database.Connection
  • Microsoft.EntityFrameworkCore.Database.Transaction
  • Microsoft.EntityFrameworkCore.Migrations
  • Microsoft.EntityFrameworkCore.Infrastructure
  • Microsoft.EntityFrameworkCore.Migrations
  • Microsoft.EntityFrameworkCore.Model
  • Microsoft.EntityFrameworkCore.Model.Validation
  • Microsoft.EntityFrameworkCore.Query
  • Microsoft.EntityFrameworkCore.Update

追踪

.NET Aspire PostgreSQL Entity Framework Core 集成将使用 OpenTelemetry发出以下跟踪活动:

  • Npgsql

指标

.NET Aspire PostgreSQL Entity Framework Core 集成将使用 OpenTelemetry发出以下指标:

  • Microsoft.EntityFrameworkCore:

    • ec_Microsoft_EntityFrameworkCore_active_db_contexts
    • ec_Microsoft_EntityFrameworkCore_total_queries
    • ec_Microsoft_EntityFrameworkCore_queries_per_second
    • ec_Microsoft_EntityFrameworkCore_total_save_changes
    • ec_Microsoft_EntityFrameworkCore_save_changes_per_second
    • ec_Microsoft_EntityFrameworkCore_compiled_query_cache_hit_rate
    • ec_Microsoft_Entity_total_execution_strategy_operation_failures
    • ec_Microsoft_E_execution_strategy_operation_failures_per_second
    • ec_Microsoft_EntityFramew_total_optimistic_concurrency_failures
    • ec_Microsoft_EntityF_optimistic_concurrency_failures_per_second
  • Npgsql:

    • ec_Npgsql_bytes_written_per_second
    • ec_Npgsql_bytes_read_per_second
    • ec_Npgsql_commands_per_second
    • ec_Npgsql_total_commands
    • ec_Npgsql_current_commands
    • ec_Npgsql_failed_commands
    • ec_Npgsql_prepared_commands_ratio
    • ec_Npgsql_connection_pools
    • ec_Npgsql_multiplexing_average_commands_per_batch
    • ec_Npgsql_multiplexing_average_write_time_per_batch

另请参阅