From 2576d09be4e30803d31a1c08948f93e8b7dd2893 Mon Sep 17 00:00:00 2001 From: Sadeq Abu-Hattem Date: Wed, 9 Sep 2026 22:17:48 +0300 Subject: [PATCH] Register the sample's DbContext on the plain Npgsql provider The sample referenced Aspire.Npgsql.EntityFrameworkCore.PostgreSQL and called builder.AddNpgsqlDbContext("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(), 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 --- Directory.Packages.props | 8 ++--- .../DotNetBoost.Settings.AppHost/AppHost.cs | 5 +++ samples/SampleApp/Program.cs | 32 ++++++++++++++++++- samples/SampleApp/SampleApp.csproj | 3 +- ...tNetBoost.Settings.IntegrationTests.csproj | 1 - 5 files changed, 42 insertions(+), 7 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index e14f3e6..73276d1 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -30,7 +30,9 @@ - + + + @@ -78,9 +80,7 @@ - - - + diff --git a/aspire/DotNetBoost.Settings.AppHost/AppHost.cs b/aspire/DotNetBoost.Settings.AppHost/AppHost.cs index 85a9b5f..cbbcf0a 100644 --- a/aspire/DotNetBoost.Settings.AppHost/AppHost.cs +++ b/aspire/DotNetBoost.Settings.AppHost/AppHost.cs @@ -85,6 +85,11 @@ .WithReference(redis) .WaitFor(redis) .WithEnvironment("Settings__EncryptionKey", encryptionKey) + // /health carries the AddDbContextCheck registered in samples/SampleApp/Program.cs, so + // this is what makes the dashboard's WaitFor(api) below hold until Postgres actually + // answers rather than merely until the process is up. MapDefaultEndpoints only maps + // /health in Development — drop this line if you ever publish this AppHost. + .WithHttpHealthCheck("/health") .WithExternalHttpEndpoints(); // ── Dashboard — clients/dashboard (Nuxt) ───────────────────────────────────── diff --git a/samples/SampleApp/Program.cs b/samples/SampleApp/Program.cs index fc99f60..60246cc 100644 --- a/samples/SampleApp/Program.cs +++ b/samples/SampleApp/Program.cs @@ -1,5 +1,8 @@ using DotNetBoost.Settings.Core.Interfaces; using Microsoft.EntityFrameworkCore; +using OpenTelemetry; +using OpenTelemetry.Metrics; +using OpenTelemetry.Trace; using SampleApp; using SampleApp.Caching; using SampleApp.Settings; @@ -23,7 +26,34 @@ // block, uncomment the one you want, flip the matching ItemGroup in SampleApp.csproj, // the provider block in AppHost.cs, and the DatabaseProvider in AppDbContext.cs. // ───────────────────────────────────────────────────────────────────────────── -builder.AddNpgsqlDbContext("settingsdb"); +builder.Services.AddDbContext(opt => + opt.UseNpgsql( + builder.Configuration.GetConnectionString("settingsdb"), + // A cold Postgres container refuses a few connections before it accepts any, so + // retry transient failures instead of failing the first request after a restart. + // Bounded deliberately: the readiness probe below runs through this same strategy, + // and the default policy (6 retries backing off to 30s) makes it take about a + // minute to report a database that is plainly gone. + npgsql => npgsql.EnableRetryOnFailure( + maxRetryCount: 3, + maxRetryDelay: TimeSpan.FromSeconds(2), + errorCodesToAdd: null))); + +// The two registrations below come free with Aspire.Npgsql.EntityFrameworkCore.PostgreSQL +// and have to be written out when the plain provider is used, as it is here: +// readiness — without it /health answers Healthy while Postgres is unreachable, which +// makes it useless to anything that gates traffic on it. Nothing polls it +// today: add .WithHttpHealthCheck("/health") to the api resource in +// AppHost.cs to make WaitFor(api) wait on the database too. +// telemetry — Npgsql's ActivitySource and Meter, so a trace on the dashboard shows the +// SQL a request ran instead of stopping at the HTTP span, and the Metrics +// page carries the connection-pool counters. +builder.Services.AddHealthChecks() + .AddDbContextCheck(); + +builder.Services.AddOpenTelemetry() + .WithTracing(tracing => tracing.AddSource("Npgsql")) + .WithMetrics(metrics => metrics.AddMeter("Npgsql")); // ───────────────────────────────────────────────────────────────────────────── // Storage provider — ALTERNATIVE: SQL Server (Entity Framework Core) diff --git a/samples/SampleApp/SampleApp.csproj b/samples/SampleApp/SampleApp.csproj index 3f8cdff..b972e06 100644 --- a/samples/SampleApp/SampleApp.csproj +++ b/samples/SampleApp/SampleApp.csproj @@ -22,7 +22,8 @@ in Program.cs and the container started by aspire/DotNetBoost.Settings.AppHost. --> - + + diff --git a/tests/DotNetBoost.Settings.IntegrationTests/DotNetBoost.Settings.IntegrationTests.csproj b/tests/DotNetBoost.Settings.IntegrationTests/DotNetBoost.Settings.IntegrationTests.csproj index 919f0c9..6c93193 100644 --- a/tests/DotNetBoost.Settings.IntegrationTests/DotNetBoost.Settings.IntegrationTests.csproj +++ b/tests/DotNetBoost.Settings.IntegrationTests/DotNetBoost.Settings.IntegrationTests.csproj @@ -20,6 +20,5 @@ -