DEV Community

Stanislav Berkov
Stanislav Berkov

Posted on

Switching environments in dotnet project using user-secrets

In my practice I have to switch between environments quite often. This happens due to different reasons. I have environments like: dev, sqa1, sqa2, uat. One environment might be under deployment and you need to switch to another, working one. Sometimes some bug can be reproduced on a particular environment and you switch to it to reproduce it locally under debugger using database and external servers from that environment. Potentially you can have dev.yaml, sqa1.yaml, sqa2.yaml, uat.yaml files in your git repo and replace appsettings.yaml with the one you need. This approach has major drawback: you can occasionally push default configuration change into repo. To avoid that you can use dotnet user-secrets feature.

Just add user secrets config source to your console application (you don't need to add it explicitly for aspnet app; it is already there).

        builder.Configuration
            // other config sources
            .AddUserSecrets<Program>()
Enter fullscreen mode Exit fullscreen mode

After that you can add secret to project secrete store like

dotnet user-secrets --id your-project-id set "STORAGE:HOST" "cassndra.rke4.dev"
Enter fullscreen mode Exit fullscreen mode

You also need to specify secrete id in csproj like

<Project>
    <PropertyGroup>
        <UserSecretsId>your-project-id</UserSecretsId>
    </PropertyGroup>
...
</Project>
Enter fullscreen mode Exit fullscreen mode

dotnet configuration manager will load it using standard ":" separator delimiter.

Then, for switching between environments I created secret.txt files with values like "KEY1=VALUE1" and created script to load them:

#!/usr/bin/env zsh
# Reads lines like `MODES:HOST=sftp01.sqa` from secrets.txt and runs:
#   dotnet user-secrets --id trader-analytics set "MODES:HOST" "sftp01.sqa"
#
# After all secrets are applied, waits for Enter, then clears them and lists
# the (now empty) secret store to confirm.
#

set -euo pipefail

SECRETS_FILE="${0:A:h}/secrets.txt"
USER_SECRETS_ID="${USER_SECRETS_ID:-your-project-id}"

if [[ ! -f "$SECRETS_FILE" ]]; then
  print -u2 "error: $SECRETS_FILE not found"
  exit 1
fi

process_line() {
  local line="$1"

  # Trim leading/trailing whitespace
  line="${line##[[:space:]]##}"
  line="${line%%[[:space:]]##}"

  # Skip blanks and comments
  [[ -z "$line" || "$line" == \#* ]] && return 0

  if [[ "$line" != *=* ]]; then
    print -u2 "skip (no '='): $line"
    return 0
  fi

  local key="${line%%=*}"
  local value="${line#*=}"

  if [[ -z "$key" ]]; then
    print -u2 "skip (empty key): $line"
    return 0
  fi

  print -r -- "+ dotnet user-secrets --id $USER_SECRETS_ID set \"$key\" \"$value\""
  dotnet user-secrets --id "$USER_SECRETS_ID" set "$key" "$value"
}

while IFS= read -r line || [[ -n "$line" ]]; do
  process_line "$line"
done < "$SECRETS_FILE"

print
print -- "All secrets applied. Press Enter to clear them..."
read -r _

print -- "+ dotnet user-secrets --id $USER_SECRETS_ID clear"
dotnet user-secrets --id "$USER_SECRETS_ID" clear

print -- "+ dotnet user-secrets --id $USER_SECRETS_ID list"
dotnet user-secrets --id "$USER_SECRETS_ID" list
Enter fullscreen mode Exit fullscreen mode

Top comments (0)