Azure PostgreSQL EF Core Client integration reference

Azure Database for PostgreSQL logo

To get started with the Aspire Azure PostgreSQL EF Core integrations, follow the Get started with Azure PostgreSQL integrations guide.

This article includes full details about the Aspire Azure PostgreSQL EF Core Client integration, which allows you to connect to and interact with Azure PostgreSQL databases from your Aspire consuming projects using Entity Framework Core.

Installation

To get started with the Aspire Azure PostgreSQL Entity Framework Core client integration, install the 📦 Aspire.Azure.Npgsql.EntityFrameworkCore.PostgreSQL NuGet package in the client-consuming project, that is, the project for the application that uses the Azure PostgreSQL EF Core client. The Aspire Azure PostgreSQL Entity Framework Core client integration registers your desired DbContext subclass instances that you can use to interact with PostgreSQL.

Install the NuGet package
dotnet add package Aspire.Azure.Npgsql.EntityFrameworkCore.PostgreSQL

Add Azure Npgsql database context

The Azure PostgreSQL connection can be consumed using the EF Core client integration by calling the AddAzureNpgsqlDbContext:

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

Note

To use this code, you must create a DbContext class called YourDbContext in your project. This class defines your database schema using EF Core. For more information on creating and configuring a DbContext, see DbContext Lifetime, Configuration, and Initialization in the EF Core documentation.

Tip

The connectionName parameter must match the name used when adding the PostgreSQL server resource in the AppHost project.

The preceding code snippet demonstrates how to use the AddAzureNpgsqlDbContext method to register a YourDbContext (that's pooled for performance) instance that uses Azure authentication (Microsoft Entra ID). This "postgresdb" connection name corresponds to a connection string configuration value.

After adding YourDbContext to the builder, you can get the YourDbContext instance using dependency injection. For example, to retrieve your data source object from an example service define it as a constructor parameter and ensure the ExampleService class is registered with the dependency injection container:

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

For more information on dependency injection, see .NET dependency injection.

Properties of the Azure PostgreSQL resources

When you use the WithReference method to pass an Azure PostgreSQL flexible server or database resource from the AppHost project to a consuming client project, several properties are available to use in the consuming project.

Aspire exposes each property as an environment variable named [RESOURCE]_[PROPERTY]. For instance, the Uri property of a resource called postgresdb becomes POSTGRESDB_URI.

Azure PostgreSQL flexible server resource

The Azure PostgreSQL flexible server resource exposes the following connection properties:

Property Name Description
Host The hostname or IP address of the Azure PostgreSQL flexible server
Port The port number the PostgreSQL server is listening on
Username The username for authentication. This property is emitted when the server is configured for password authentication and may be omitted when using the default Microsoft Entra ID authentication.
Password The password for authentication. This property is emitted only when using password authentication and is not present when using Microsoft Entra ID authentication.
Uri The connection URI in postgresql:// format that does not embed credentials, for example postgresql://{Host}:{Port}?sslmode=Require
JdbcConnectionString JDBC-format connection string without embedded credentials, for example jdbc:postgresql://{Host}:{Port}?sslmode=require&authenticationPluginClassName=com.azure.identity.extensions.jdbc.postgresql.AzurePostgresqlAuthenticationPlugin. User and password credentials are provided as separate Username and Password properties when using password authentication.

Azure PostgreSQL database resource

The Azure PostgreSQL database resource inherits all properties from its parent AzurePostgresFlexibleServerResource and adds:

Property Name Description
Uri The connection URI in postgresql:// format that does not embed credentials, for example postgresql://{Host}:{Port}/{DatabaseName}?sslmode=Require. Credentials are exposed via other properties.
JdbcConnectionString JDBC connection string including the database name without embedded credentials, for example jdbc:postgresql://{Host}:{Port}/{DatabaseName}?sslmode=require&authenticationPluginClassName=com.azure.identity.extensions.jdbc.postgresql.AzurePostgresqlAuthenticationPlugin. User and password credentials are provided as separate Username and Password properties when using password authentication.
DatabaseName The name of the database

Enrich an Npgsql database context

You may prefer to use the standard Entity Framework method to obtain a database context and add it to the dependency injection container:

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

Note

The connection string name that you pass to the GetConnectionString method must match the name used when adding the PostgreSQL server resource in the AppHost project. For more information, see Add an Azure Database for PostgreSQL resource.

You have more flexibility when you create the database context in this way, for example:

  • You can reuse existing configuration code for the database context without rewriting it for Aspire.
  • You can use Entity Framework Core interceptors to modify database operations.
  • You can choose not to use Entity Framework Core context pooling, which may perform better in some circumstances.

If you use this method, you can enhance the database context with Aspire retries, health checks, logging, and telemetry features by calling the EnrichAzureNpgsqlDbContext method:

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

The settings parameter is an instance of the AzureNpgsqlEntityFrameworkCorePostgreSQLSettings class.

You might also need to configure specific options of Npgsql, or register a System.Data.Entity.DbContext in other ways. In this case, you do so by calling the EnrichAzureNpgsqlDbContext extension method, as shown in the following example:

var connectionString = builder.Configuration.GetConnectionString("postgresdb");
  
builder.Services.AddDbContextPool<YourDbContext>(
    dbContextOptionsBuilder => dbContextOptionsBuilder.UseNpgsql(connectionString));
  
builder.EnrichAzureNpgsqlDbContext<YourDbContext>();

Configuration

The Aspire Azure PostgreSQL EntityFrameworkCore Npgsql integration provides multiple options to configure the database connection based on the requirements and conventions of your project.

Use a connection string

When using a connection string defined in the ConnectionStrings configuration section, you provide the name of the connection string when calling AddAzureNpgsqlDataSource:

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

The connection string is retrieved from the ConnectionStrings configuration section, for example, consider the following JSON configuration:

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

For more information on how to configure the connection string, see the Npgsql connection string documentation.

Note

The username and password are automatically inferred from the credential provided in the settings.

Use configuration providers

The Aspire Azure PostgreSQL EntityFrameworkCore Npgsql integration supports Microsoft.Extensions.Configuration. It loads the AzureNpgsqlEntityFrameworkCorePostgreSQLSettings from configuration using the Aspire:Npgsql:EntityFrameworkCore:PostgreSQL key. For example, consider the following appsettings.json file that configures some of the available options:

{
  "Aspire": {
    "Npgsql": {
      "EntityFrameworkCore": {
        "PostgreSQL": {
          "DisableHealthChecks": true,
          "DisableTracing": true
        }
      }
    }
  }
}

Use inline delegates

You can configure settings in code, by passing the Action<AzureNpgsqlEntityFrameworkCorePostgreSQLSettings> configureSettings delegate to set up some or all the options inline, for example to disable health checks from code:

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

Alternatively, you can use the EnrichAzureNpgsqlDbContext extension method to configure the settings:

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

Use the AzureNpgsqlEntityFrameworkCorePostgreSQLSettings.Credential property to establish a connection. If no credential is configured, a default credential is used.

When the connection string contains a username and password, the credential is ignored.

Troubleshooting

In the rare case that the Username property isn't provided and the integration can't detect it using the application's Managed Identity, Npgsql throws an exception with a message similar to the following:

Npgsql.PostgresException (0x80004005): 28P01: password authentication failed for user ...

In this case you can configure the Username property in the connection string and use EnrichAzureNpgsqlDbContext, passing the connection string in UseNpgsql:

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

Configure multiple DbContext classes

If you want to register more than one DbContext with different configuration, you can use $"Aspire:Npgsql:EntityFrameworkCore:PostgreSQL:{typeof(TContext).Name}" configuration section name. The json configuration would look like:

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

Then calling the AddAzureNpgsqlDbContext method with AnotherDbContext type parameter would load the settings from Aspire:Npgsql:EntityFrameworkCore:PostgreSQL:AnotherDbContext section.

builder.AddAzureNpgsqlDbContext<AnotherDbContext>();

By default, the Aspire PostgreSQL Entity Framework Core integrations handles the following:

  • Adds the DbContextHealthCheck, which calls EF Core's CanConnectAsync method. The name of the health check is the name of the TContext type.
  • Integrates with the /health HTTP endpoint, which specifies all registered health checks must pass for app to be considered ready to accept traffic

Observability and telemetry

Aspire integrations automatically set up Logging, Tracing, and Metrics configurations.

Logging

The Aspire PostgreSQL Entity Framework Core integration uses the following Log categories:

  • 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

Tracing

The Aspire PostgreSQL Entity Framework Core integration will emit the following tracing activities using OpenTelemetry:

  • Npgsql

Metrics

The Aspire PostgreSQL Entity Framework Core integration will emit the following metrics using 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