SAPFIAI uses ASP.NET Core’s configuration system to manage application settings across different environments. Configuration is loaded from multiple sources with a clear precedence order.
Configuration Files
Configuration files are located in the src/Web/ directory:
src/Web/
├── appsettings.json # Base configuration for all environments
├── appsettings.Development.json # Development overrides
├── appsettings.Production.json # Production overrides
└── .env # Local environment variables (not in source control)
Base Configuration
The main configuration file is appsettings.json:
{
"ConnectionStrings" : {
"DefaultConnection" : "Server=(localdb) \\ mssqllocaldb;Database=SAPFIAIDb;Trusted_Connection=True;MultipleActiveResultSets=true"
},
"Jwt" : {
"Key" : "CHANGE-ME-USE-USER-SECRETS-OR-ENV-VARS" ,
"Issuer" : "SAPFIAI" ,
"Audience" : "SAPFIAI-Users" ,
"ExpireMinutes" : "60" ,
"RefreshTokenExpirationDays" : "7"
},
"Security" : {
"RefreshToken" : {
"ExpirationDays" : 7 ,
"MaxActiveTokensPerUser" : 5
},
"RateLimiting" : {
"MaxAttemptsPerIp" : 5 ,
"WindowMinutes" : 15 ,
"IpBlockDurationMinutes" : 60
},
"AccountLock" : {
"MaxFailedAttempts" : 5 ,
"LockoutMinutes" : 15 ,
"ResetFailedAttemptsAfterMinutes" : 60
},
"BlackList" : {
"EnableAutoBlock" : true ,
"AutoBlockAfterAttempts" : 10 ,
"AutoBlockDurationHours" : 24
}
},
"App" : {
"BaseUrl" : "https://localhost:5001"
},
"Logging" : {
"LogLevel" : {
"Default" : "Information" ,
"Microsoft" : "Warning" ,
"Microsoft.Hosting.Lifetime" : "Information"
}
},
"AllowedHosts" : "*"
}
Never commit sensitive values like JWT keys to source control. Use user secrets or environment variables instead.
Environment-Specific Configuration
Development Settings
appsettings.Development.json overrides settings for local development:
{
"Logging" : {
"LogLevel" : {
"Default" : "Information" ,
"Microsoft" : "Warning" ,
"Microsoft.AspNetCore.SpaProxy" : "Information" ,
"Microsoft.Hosting.Lifetime" : "Information"
}
}
}
Production Settings
appsettings.Production.json contains production-specific overrides:
{
"Logging" : {
"LogLevel" : {
"Default" : "Warning" ,
"Microsoft" : "Warning" ,
"Microsoft.Hosting.Lifetime" : "Information"
}
}
}
Setting the Environment
Control which configuration file is loaded:
# Development (default)
export ASPNETCORE_ENVIRONMENT = Development
dotnet run --project src/Web
# Production
export ASPNETCORE_ENVIRONMENT = Production
dotnet run --project src/Web
# Staging
export ASPNETCORE_ENVIRONMENT = Staging
dotnet run --project src/Web
Environment Variables
Environment variables override configuration files and are loaded from .env files.
.env File Loading
The application loads .env files automatically from Program.cs:4:
// Load environment variables from .env file BEFORE building configuration
var possibleEnvPaths = new []
{
Path . Combine ( Directory . GetCurrentDirectory (), ".env" ),
Path . Combine ( Directory . GetCurrentDirectory (), ".." , ".." , ".env" ),
Path . Combine ( AppDomain . CurrentDomain . BaseDirectory , ".env" ),
Path . Combine ( AppDomain . CurrentDomain . BaseDirectory , ".." , ".." , ".." , ".." , ".." , ".env" )
};
foreach ( var envPath in possibleEnvPaths )
{
if ( File . Exists ( envPath ))
{
Console . WriteLine ( $"🔧 Cargando variables de entorno desde: { Path . GetFullPath ( envPath )} " );
foreach ( var line in File . ReadAllLines ( envPath ))
{
if ( string . IsNullOrWhiteSpace ( line ) || line . StartsWith ( "#" ))
continue ;
var parts = line . Split ( '=' , 2 );
if ( parts . Length == 2 )
{
var key = parts [ 0 ]. Trim ();
var value = parts [ 1 ]. Trim ();
Environment . SetEnvironmentVariable ( key , value );
}
}
break ;
}
}
Creating a .env File
Create a .env file in your project root (add to .gitignore):
# Database
ConnectionStrings__DefaultConnection = Server = localhost ; Database = SAPFIAIDb ; User Id=sa ; Password = YourPassword123!
# JWT
Jwt__Key = your-super-secret-jwt-key-min-32-characters-long
Jwt__Issuer = SAPFIAI
Jwt__Audience = SAPFIAI-Users
# App Settings
App__BaseUrl = https://your-domain.com
# Skip database initialization
SKIP_DB_INIT = false
Use double underscores (__) to represent nested configuration sections.
Environment Variable Syntax
Map environment variables to configuration:
# appsettings.json path: ConnectionStrings:DefaultConnection
# Environment variable:
ConnectionStrings__DefaultConnection = "Server=...;"
# appsettings.json path: Jwt:Key
# Environment variable:
Jwt__Key = "your-secret-key"
# appsettings.json path: Security:RateLimiting:MaxAttemptsPerIp
# Environment variable:
Security__RateLimiting__MaxAttemptsPerIp = 10
Connection Strings
Development Connection String
For local development with SQL Server LocalDB:
{
"ConnectionStrings" : {
"DefaultConnection" : "Server=(localdb) \\ mssqllocaldb;Database=SAPFIAIDb;Trusted_Connection=True;MultipleActiveResultSets=true"
}
}
Production Connection String
For production SQL Server:
# .env file
ConnectionStrings__DefaultConnection = Server = prod-server.database.windows.net ; Database = SAPFIAIDb ; User Id=sapfiai_user ; Password = *** ; Encrypt = True ; TrustServerCertificate = False ;
SQLite for Testing
For lightweight testing scenarios:
{
"ConnectionStrings" : {
"DefaultConnection" : "Data Source=sapfiai.db"
}
}
Use SQL Server LocalDB for development to match production behavior more closely.
Configuration Sections
JWT Configuration
Manage JWT authentication settings:
{
"Jwt" : {
"Key" : "your-secret-key-must-be-at-least-32-chars" ,
"Issuer" : "SAPFIAI" ,
"Audience" : "SAPFIAI-Users" ,
"ExpireMinutes" : "60" ,
"RefreshTokenExpirationDays" : "7"
}
}
Secret key for signing JWTs. Must be at least 32 characters. Never commit to source control.
Token issuer identifier (typically your application name)
Intended audience for the token (typically your API consumers)
Access token expiration time in minutes
RefreshTokenExpirationDays
Refresh token expiration time in days
Security Configuration
Configure security features like rate limiting and account lockout:
{
"Security" : {
"RefreshToken" : {
"ExpirationDays" : 7 ,
"MaxActiveTokensPerUser" : 5
},
"RateLimiting" : {
"MaxAttemptsPerIp" : 5 ,
"WindowMinutes" : 15 ,
"IpBlockDurationMinutes" : 60
},
"AccountLock" : {
"MaxFailedAttempts" : 5 ,
"LockoutMinutes" : 15 ,
"ResetFailedAttemptsAfterMinutes" : 60
},
"BlackList" : {
"EnableAutoBlock" : true ,
"AutoBlockAfterAttempts" : 10 ,
"AutoBlockDurationHours" : 24
}
}
}
Logging Configuration
Control logging levels per namespace:
{
"Logging" : {
"LogLevel" : {
"Default" : "Information" ,
"Microsoft" : "Warning" ,
"Microsoft.Hosting.Lifetime" : "Information" ,
"Microsoft.EntityFrameworkCore" : "Warning"
}
}
}
Log levels (from most to least verbose):
Trace - Very detailed diagnostic information
Debug - Debugging information
Information - General informational messages
Warning - Warning messages
Error - Error messages
Critical - Critical failure messages
None - No logging
App Configuration
Application-specific settings:
{
"App" : {
"BaseUrl" : "https://localhost:5001" ,
"AllowedOrigins" : [
"http://localhost:3000" ,
"https://your-frontend.com"
]
}
}
User Secrets (Development)
For local development, use User Secrets to store sensitive data outside of your project:
Initialize User Secrets
cd src/Web
dotnet user-secrets init
Set Secrets
# JWT Key
dotnet user-secrets set "Jwt:Key" "your-super-secret-jwt-key-for-development"
# Connection String
dotnet user-secrets set "ConnectionStrings:DefaultConnection" "Server=localhost;Database=SAPFIAIDb;User Id=sa;Password=DevPassword123!"
List Secrets
Remove Secrets
dotnet user-secrets remove "Jwt:Key"
# Remove all secrets
dotnet user-secrets clear
User secrets are stored in your user profile directory and never committed to source control.
Accessing Configuration
In Dependency Injection
Inject IConfiguration or use the Options pattern:
public class MyService
{
private readonly IConfiguration _configuration ;
public MyService ( IConfiguration configuration )
{
_configuration = configuration ;
}
public void DoSomething ()
{
var connectionString = _configuration . GetConnectionString ( "DefaultConnection" );
var jwtKey = _configuration [ "Jwt:Key" ];
var maxAttempts = _configuration . GetValue < int >( "Security:RateLimiting:MaxAttemptsPerIp" );
}
}
Using Options Pattern
Define strongly-typed configuration classes:
// Configuration class
public class JwtSettings
{
public string Key { get ; set ; } = string . Empty ;
public string Issuer { get ; set ; } = string . Empty ;
public string Audience { get ; set ; } = string . Empty ;
public int ExpireMinutes { get ; set ; }
public int RefreshTokenExpirationDays { get ; set ; }
}
// Register in DependencyInjection.cs
services . Configure < JwtSettings >( configuration . GetSection ( "Jwt" ));
// Inject in service
public class TokenService
{
private readonly JwtSettings _jwtSettings ;
public TokenService ( IOptions < JwtSettings > jwtSettings )
{
_jwtSettings = jwtSettings . Value ;
}
public string GenerateToken ()
{
var key = _jwtSettings . Key ;
var issuer = _jwtSettings . Issuer ;
// ...
}
}
Configuration Precedence
Configuration sources are applied in this order (later sources override earlier ones):
appsettings.json
Base configuration for all environments
appsettings.{Environment}.json
Environment-specific overrides
User Secrets (Development only)
Local developer secrets
Environment Variables
System and .env file variables
Command Line Arguments
Arguments passed to dotnet run
Example Precedence
Given these configurations:
// appsettings.json
{
"Jwt" : {
"Key" : "default-key" ,
"ExpireMinutes" : "60"
}
}
// appsettings.Production.json
{
"Jwt" : {
"ExpireMinutes" : "30"
}
}
# .env
Jwt__Key = production-secret-key
In Production environment:
Jwt:Key = "production-secret-key" (from .env)
Jwt:ExpireMinutes = "30" (from appsettings.Production.json)
Special Configuration
Skip Database Initialization
Prevent automatic database initialization on startup:
# Environment variable
export SKIP_DB_INIT = true
# Or in appsettings.json
{
"SkipDatabaseInitialization" : true
}
Implemented in Program.cs:51:
var skipDatabaseInitialization = builder . Configuration . GetValue < bool >( "SkipDatabaseInitialization" )
|| string . Equals ( Environment . GetEnvironmentVariable ( "SKIP_DB_INIT" ), "true" , StringComparison . OrdinalIgnoreCase )
|| Environment . GetEnvironmentVariable ( "SKIP_DB_INIT" ) == "1" ;
CORS Configuration
Configure Cross-Origin Resource Sharing for frontend applications:
{
"Cors" : {
"AllowedOrigins" : [
"http://localhost:3000" ,
"https://your-app.com"
],
"AllowedMethods" : [ "GET" , "POST" , "PUT" , "DELETE" ],
"AllowedHeaders" : [ "*" ],
"AllowCredentials" : true
}
}
Deployment Configuration
Azure App Service
Set configuration in Application Settings (environment variables):
ConnectionStrings__DefaultConnection = Server = ... ;
Jwt__Key = ...
ASPNETCORE_ENVIRONMENT = Production
Docker
Pass environment variables in docker run:
docker run -d \
-e ConnectionStrings__DefaultConnection="Server=...;" \
-e Jwt__Key="your-production-key" \
-e ASPNETCORE_ENVIRONMENT=Production \
-p 80:8080 \
sapfiai-api
Or use a .env file with Docker Compose:
# docker-compose.yml
services :
api :
image : sapfiai-api
env_file :
- .env.production
ports :
- "80:8080"
Kubernetes
Use ConfigMaps and Secrets:
apiVersion : v1
kind : Secret
metadata :
name : sapfiai-secrets
type : Opaque
stringData :
jwt-key : your-production-jwt-key
connection-string : Server=...;
---
apiVersion : v1
kind : ConfigMap
metadata :
name : sapfiai-config
data :
ASPNETCORE_ENVIRONMENT : "Production"
Logging__LogLevel__Default : "Warning"
Troubleshooting
Configuration Not Loading
Verify configuration is being read:
// In Startup or Program.cs
var config = builder . Configuration . AsEnumerable ();
foreach ( var item in config )
{
Console . WriteLine ( $" { item . Key } = { item . Value } " );
}
Environment Variables Not Working
Check environment variable syntax:
# Wrong (Linux/Mac)
JWT:KEY =value # Colon not supported
# Correct
Jwt__Key = value # Double underscore
Connection String Errors
Test connection string:
var connectionString = configuration . GetConnectionString ( "DefaultConnection" );
Console . WriteLine ( $"Connection string: { connectionString } " );
Next Steps
Database Migrations Apply schema changes to your configured database
Deployment Deploy with production configuration