ConnectionStrings

Store, override and read connection strings with the ConnectionStrings section and GetConnectionString, and fail fast when one is missing.

Signature
"ConnectionStrings": { "Orders": "Host=...;Database=orders" }  |  ConnectionStrings__Orders=...  |  config.GetConnectionString("Orders")
  • Added in .NET ASP.NET Core 1.0

Parameters

ParameterTypeDescription
$namestringKey under the ConnectionStrings section. Case-insensitive like every configuration key.

Return value

string?GetConnectionString(name) is shorthand for configuration.GetSection("ConnectionStrings")[name]: the string from whichever configuration source set it last, or null when no source set it.

Errors

Never throws. A missing name returns null; the database driver then fails at the first query (for Npgsql: InvalidOperationException, The ConnectionString property has not been initialized), so validate at startup.

ConnectionStrings is an ordinary configuration section with one convention attached: IConfiguration.GetConnectionString("Orders") reads ConnectionStrings:Orders. Nothing else is special. The value goes through the same provider stack as any key, so appsettings.json, the environment file, user secrets, environment variables and the command line can all set it, and the last source added wins. In a container, ConnectionStrings__Orders (double underscore for the colon) overrides the JSON value.

Where each part of the string should live

PartWhereWhy
Host, database, pool size, timeoutsappsettings.{Environment}.jsonNot secret, reviewed in pull requests
Password or whole stringUser secrets locally; a secret store or Kubernetes Secret in production, injected as ConnectionStrings__OrdersNever in source control or images
Aspire-orchestrated resourcesInjected by the AppHost as ConnectionStrings__<resource>The name in WithReference must match GetConnectionString

Azure App Service also exposes connection strings as environment variables with type prefixes such as SQLCONNSTR_Orders and CUSTOMCONNSTR_Orders; the default environment variable provider strips the prefix and maps them to ConnectionStrings:Orders.

The null trap

GetConnectionString never throws. A typo (ConnectionStrings__Order in the manifest, "Orders" in code) returns null, AddDbContext or NpgsqlDataSource registration accepts it, and the pod passes its liveness probe. The first request then fails with "The ConnectionString property has not been initialized" or a provider-specific equivalent. Fail at startup instead: read it with ?? throw new InvalidOperationException(...) in Program.cs, or bind it into options with ValidateOnStart. A readiness check that opens a connection catches a wrong password before the pod receives traffic.

Logging and rotation

Do not log the raw string; it usually contains the password. DbConnectionStringBuilder (System.Data.Common, no package needed) parses the key=value format so you can remove the password before logging what the app is connecting to. It does not know provider synonyms, so remove every spelling (Password, Pwd, and PSW for Npgsql), or use the provider's own builder (NpgsqlConnectionStringBuilder, SqlConnectionStringBuilder), which normalises them. Logging only the host and database is safer still. Rotating a password means changing the secret and restarting pods: data sources and DbContext pools capture the string when they are built, so a reloaded configuration value does not reach connections that already exist.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Point staging pods at a different PostgreSQL host by overriding ConnectionStrings__Orders from a Kubernetes Secret
  • Keep the reporting endpoints on a read replica with a second ConnectionStrings:Reporting entry and a separate data source
  • Crash at startup with a clear message when a manifest typo leaves ConnectionStrings:Orders unset

Frequently asked questions

Why does GetConnectionString return null?

No configuration source set ConnectionStrings:<name>. Check the spelling in code and in the environment variable (ConnectionStrings__Orders, two underscores), and that the variable reaches the process. It never throws, so add your own startup check.

Can I put only the password in an environment variable?

Not with plain configuration: a value replaces the whole string. Either inject the full string as a secret, or keep the parts as separate settings and build the string with NpgsqlConnectionStringBuilder or DbConnectionStringBuilder at startup.

Does changing the connection string in appsettings.json take effect without restart?

The configuration value reloads, but data sources, pools and DbContext options captured it at startup. Treat connection strings as restart-only.

More examples

appsettings.json without the secret

Configuration does not merge parts of a string: when <code>ConnectionStrings__Orders</code> is set in the environment it replaces this whole value, so the secret must hold the complete string. The JSON value then serves only as documentation and as the local default.

Example · json
{
  "ConnectionStrings": {
    // Password comes from ConnectionStrings__Orders in the environment
    "Orders": "Host=orders-db.internal;Port=5432;Database=orders;Username=orders_api;Maximum Pool Size=50;Timeout=5",
    "Reporting": "Host=orders-replica.internal;Port=5432;Database=orders;Username=reports;Maximum Pool Size=10"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information"
    }
  }
}

Kubernetes Secret feeding the connection string

<code>envFrom</code> turns each key of the Secret into an environment variable, and the double underscore becomes the configuration colon. Pods read environment variables only at start, so after rotating the password run <code>kubectl rollout restart</code>.

Example · yaml
apiVersion: v1
kind: Secret
metadata:
  name: orders-api-db
type: Opaque
stringData:
  ConnectionStrings__Orders: "Host=orders-db.internal;Port=5432;Database=orders;Username=orders_api;Password=<from-secret-store>;Maximum Pool Size=50"
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: orders-api
spec:
  selector:
    matchLabels:
      app: orders-api
  template:
    metadata:
      labels:
        app: orders-api
    spec:
      containers:
        - name: api
          image: registry.example.com/orders-api:1.8.2
          envFrom:
            - secretRef:
                name: orders-api-db

Fail fast and use the string once

The process exits before it binds a port, so Kubernetes shows CrashLoopBackOff with a clear message instead of a healthy pod failing every query. The log line keeps only host and database, which is what you need when debugging a wrong-environment connection. Removing just <code>Password</code> is not enough: <code>DbConnectionStringBuilder</code> does not map synonyms, so a string written with <code>Pwd=</code> would be logged with the secret.

Example · csharp
using System.Data.Common;

var builder = WebApplication.CreateBuilder(args);

var ordersDb = builder.Configuration.GetConnectionString("Orders");
if (string.IsNullOrWhiteSpace(ordersDb))
{
    throw new InvalidOperationException(
        "ConnectionStrings:Orders is not set. Set ConnectionStrings__Orders in the environment.");
}

builder.Services.AddSingleton(new OrdersDatabase(ordersDb));
var app = builder.Build();

// Log only where it points; never the remaining string, which may hold Pwd= or PSW=.
var parts = new DbConnectionStringBuilder { ConnectionString = ordersDb };
app.Logger.LogInformation("Orders database: host {Host}, database {Database}",
    parts.TryGetValue("Host", out var host) ? host : "(unset)",
    parts.TryGetValue("Database", out var database) ? database : "(unset)");

app.MapGet("/health/live", () => "ok");
app.Run();

public sealed record OrdersDatabase(string ConnectionString);

Discussion

  • Be the first to comment on this lesson.