Skip to content

Register the sample's DbContext on the plain Npgsql provider - #1

Merged
sadeqabuhattem merged 1 commit into
mainfrom
sample-plain-npgsql-provider
Sep 10, 2026
Merged

sadeqabuhattem merged 1 commit into
mainfrom
sample-plain-npgsql-provider

Conversation

@sadeqabuhattem

Copy link
Copy Markdown
Member

What

The sample referenced Aspire.Npgsql.EntityFrameworkCore.PostgreSQL and called builder.AddNpgsqlDbContext<AppDbContext>("settingsdb"). It now takes a direct reference on Npgsql.EntityFrameworkCore.PostgreSQL and registers the context with AddDbContext + UseNpgsql, reading the connection string the AppHost injects as ConnectionStrings__settingsdb.

Why the extra lines

That wrapper package supplied three things on its own. They are written out explicitly so the sample behaves as it did before:

  • Readiness — AddDbContextCheck<AppDbContext>(), so /health reports Unhealthy while Postgres is unreachable instead of answering Healthy.
  • Telemetry — Npgsql's ActivitySource and Meter, so a dashboard trace still shows the SQL a request ran rather than stopping at the HTTP span, and the Metrics page keeps the connection-pool counters.
  • Connection retry — bounded to 3 attempts backing off to 2s. The default policy (6 retries backing off to 30s) also governs CanConnectAsync, which left the readiness check taking about a minute to report a database that was plainly gone. Bounded, it answers in about three seconds.

The api resource also gains WithHttpHealthCheck("/health") so WaitFor(api) holds the dashboard back until Postgres actually answers, not merely until the process has started.

Coupled change

Dropping the Npgsql version pin from Directory.Packages.props requires the matching PackageReference to go from the integration tests too, or central package management fails the restore with NU1010.

Verification

Run against the full stack under the AppHost, not just compiled:

  • dotnet build -c Release -warnaserror — 0 warnings, 0 errors
  • 376 tests pass (unit 132, api 14, provider 44 — each on net8.0 and net10.0 — plus 142 integration)
  • /health against a stopped Postgres container: 503 Unhealthy in 3.1s; /alive stayed Healthy; recovered on its own once the container returned
  • Traces nest the DB call under the request: GET api/settings/mail-server/ → postgresql → settingsdb (10.85ms) + DATA redis GET → cache (0.89ms)
  • Metrics page lists the Npgsql meter with live db.client.connection.count data, split by idle/used
  • On restart, dashboard sat in Waiting while api came up healthy, then moved to Running — the new health gate working
  • End to end: reads, writes, AES-encrypted [Sensitive] columns, FluentValidation rejection (400), ETag concurrency (412 stale / 204 current), audit trail, change-notification handler, OpenAPI document

Note

MapDefaultEndpoints only maps /health in Development, so WithHttpHealthCheck would poll a 404 if this AppHost is ever published. Fine for dotnet run; worth revisiting before publish.

🤖 Generated with Claude Code

The sample referenced Aspire.Npgsql.EntityFrameworkCore.PostgreSQL and called
builder.AddNpgsqlDbContext<AppDbContext>("settingsdb"). It now takes a direct
reference on Npgsql.EntityFrameworkCore.PostgreSQL and registers the context
with AddDbContext + UseNpgsql, reading the connection string the AppHost
injects as ConnectionStrings__settingsdb.

That wrapper package supplied three things on its own, so they are written out
explicitly here to leave the sample behaving as it did:

  - readiness, via AddDbContextCheck<AppDbContext>(), so /health reports
    Unhealthy while Postgres is unreachable instead of answering Healthy
  - telemetry, via Npgsql's ActivitySource and Meter, so a dashboard trace
    still shows the SQL a request ran rather than stopping at the HTTP span,
    and the Metrics page keeps the connection-pool counters
  - connection retry, bounded to 3 attempts backing off to 2s. The default
    policy of 6 retries backing off to 30s also governs CanConnectAsync, which
    left the readiness check taking about a minute to report a database that
    was plainly gone; bounded, it answers in about three seconds.

The api resource gains WithHttpHealthCheck("/health") so that WaitFor(api)
holds the dashboard back until Postgres actually answers, not merely until the
process has started.

Dropping the Npgsql version pin from Directory.Packages.props requires the
matching PackageReference to go from the integration tests too, or central
package management fails the restore with NU1010.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@sadeqabuhattem
sadeqabuhattem merged commit da666c8 into main Sep 10, 2026
10 checks passed
@sadeqabuhattem
sadeqabuhattem deleted the sample-plain-npgsql-provider branch September 10, 2026 16:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant