Azure Blob Storage Configuration Guide
This guide explains how to configure the DWD system to use Azure Blob Storage for EPANET input files.
Overview
The DWD system uses a shared published instance of EpanetConsoleCore.exe that runs scenarios for multiple networks. Since it's a single executable used by all networks, configuration cannot rely on appsettings.json files. Instead, all Azure Blob Storage configuration is passed via command-line arguments.
Architecture
- API (
DwdApiAspNet): Reads Azure configuration from itsappsettings.jsonand passes it to EpanetConsoleCore via command-line arguments - Console Core (
EpanetConsoleCore): Receives Azure configuration via command-line arguments, which override anyappsettings.jsonpresent
Configuration Steps
1. Generate Container-Scoped SAS Tokens
You need two separate SAS tokens with different permissions:
API Token (Read + Write)
- Permissions:
Read,Write,Delete,List,Add,Create(rwdlac) - Expiry: Set far in the future (e.g., 1-2 years)
- Protocol: HTTPS only
Console Core Token (Read-Only)
- Permissions:
Read,List(rl) - Expiry: Set far in the future (e.g., 1-2 years)
- Protocol: HTTPS only
Generate via Azure Portal:
- Navigate to your Storage Account → Container
- Select "Shared access tokens" (or use "Generate SAS" in the container menu)
- Set permissions, expiry, and protocol
- Click "Generate SAS token and URL"
- Copy the token (remove leading
?if present)
2. Configure API appsettings.json
Location: dwd-api-aspnet/DwdApiAspNet/appsettings.json
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"InputFileStorage": {
"ContainerName": "dwd-input-files-mtw",
"AzureBlob": {
"ServiceUrl": "https://yourstorageaccount.blob.core.windows.net",
"ContainerSasToken": "sv=2023-01-03&ss=b&srt=c&sp=rwdlac&se=2026-12-31T23:59:59Z&st=2025-01-01T00:00:00Z&spr=https&sig=YOURSIGNATUREHERE"
}
},
"ConnectionStrings": {
"PSQLDB": "Host=localhost;Port=5432;Database=mtw_10_7_2025;Username=postgres;Password=gq010102"
},
"EpanetConsoleCore": {
"Path": "C:\\git\\gqc\\hydrotrek-dwd-suite\\epanetconsolecore\\EpanetConsoleCore\\bin\\x64\\Release\\net8.0\\publish\\EpanetConsoleCore.exe"
}
}
Important Notes:
- Remove leading
?from SAS token if present - Use read + write permissions (
sp=rwdlac) - Replace
yourstorageaccountwith your actual storage account name - Replace
YOURSIGNATUREHEREwith your actual SAS token signature
3. Console Core Configuration
⚠️ IMPORTANT: EpanetConsoleCore does NOT use appsettings.json for Azure configuration.
All Azure Blob Storage configuration MUST be passed via command-line arguments when launching EpanetConsoleCore.
Why?
- EpanetConsoleCore is a shared published executable used by multiple networks
- Using
appsettings.jsonwould cause silent failures where the wrong network's configuration is used - Command-line arguments ensure each network's API instance passes its own configuration explicitly
If you forget to pass command-line arguments, EpanetConsoleCore will fail loudly with a clear error message explaining what's missing.
How It Works
Command-Line Argument Passing
When the API launches EpanetConsoleCore, it passes Azure configuration via command-line arguments:
EpanetConsoleCore.exe "Host=localhost;..." 1 --azure-url "https://account.blob.core.windows.net" --azure-sas "sv=2023..." --container "dwd-input-files-mtw"
Arguments:
- Positional 1: Database connection string (required)
- Positional 2: Scenario ID (required)
--azure-url: Azure Blob Storage service URL--azure-sas: Container-scoped SAS token (without leading?)--container: Container name--save-inp: (Optional) Export INP file without running simulation
Configuration Enforcement
EpanetConsoleCore ONLY uses command-line arguments for Azure Blob Storage configuration.
There is NO fallback to appsettings.json. This is intentional to prevent:
- Silent failures where the wrong network's configuration is used
- Confusion about which configuration is being applied
- Accidentally running scenarios with incorrect Azure storage
If Azure configuration is missing when needed, EpanetConsoleCore will fail immediately with a clear error message:
❌ AZURE BLOB STORAGE CONFIGURATION MISSING
This scenario uses Azure Blob Storage (StorageProvider=AzureBlob), but required command-line arguments are missing:
• --azure-url
• --azure-sas
• --container
EpanetConsoleCore must be launched with Azure configuration:
EpanetConsoleCore.exe "<connection-string>" <scenario-id> \
--azure-url "https://account.blob.core.windows.net" \
--azure-sas "sv=2023..." \
--container "dwd-input-files-mtw"
💡 Note: This is a shared executable serving multiple networks.
Configuration MUST be passed via command-line arguments, not appsettings.json.
Testing
Test API Upload
- Navigate to the Input Files page in the frontend
- Click "Upload File"
- Select an
.inpfile and upload - Verify in Azure Portal that the blob appears in your container
Test Console Download
- Create a scenario using a blob-stored input file
- Click "Start Scenario"
- Monitor logs - should see:
Using blob-stored input file: your-file-name
Container: dwd-input-files-mtw, Blob: your-file-20251023-123456.inp
Downloaded <blob> to <temp-path>
Verify in Azure Portal
- Navigate to your storage account
- Open the container (
dwd-input-files-mtw) - Verify files appear with naming format:
{name}-{timestamp}.inp
Troubleshooting
"No SAS token configured for container"
Error: InvalidOperationException: No SAS token configured for container: dwd-input-files-mtw
Solutions:
- Verify
InputFileStorage:AzureBlob:ContainerSasTokenis present in API'sappsettings.json - Check for typos in configuration key names
- Ensure SAS token doesn't have leading
?
"The remote server returned an error: (403) Forbidden"
Error: RequestFailedException: The remote server returned an error: (403) Forbidden
Solutions:
- Verify SAS token has correct permissions (
rwdlacfor API,rlfor Console) - Check SAS token hasn't expired
- Ensure container name matches exactly (case-sensitive)
- Verify protocol is HTTPS only
"Container must already exist when using SAS token"
Error: InvalidOperationException: Container must already exist when using SAS token
Solutions:
- Manually create the container in Azure Portal before first use
- Ensure container name in config matches actual container name
Files not downloading/uploading
Solutions:
- Check API logs for detailed error messages
- Verify
ServiceUrlis correct format:https://accountname.blob.core.windows.net - Test SAS token manually using Azure Storage Explorer
- Ensure firewall rules allow your IP address
SAS Token Security
Best Practices
- Use container-scoped tokens, not account-scoped
- Set reasonable expiry dates (1-2 years, not indefinite)
- Use HTTPS only (
spr=https) - Limit permissions:
- API: Only grant what's needed (
rwdlac) - Console: Read-only (
rl)
- API: Only grant what's needed (
- Rotate tokens periodically (e.g., annually)
- Never commit tokens to source control
Token Rotation
When rotating SAS tokens:
- Generate new SAS tokens in Azure Portal
- Update API's
appsettings.json - Restart API service
- Verify operations work with new token
- Old tokens will expire automatically
No need to update published EpanetConsoleCore - it receives tokens from the API!
Multi-Instance Setup
For hosting multiple networks, each API instance should have its own:
- Container:
dwd-input-files-{network-name} - SAS Token: Separate token per container
appsettings.json: Configured for that specific network
Example for two networks:
MTW Instance (appsettings.json):
{
"InputFileStorage": {
"ContainerName": "dwd-input-files-mtw",
"AzureBlob": {
"ServiceUrl": "https://storage.blob.core.windows.net",
"ContainerSasToken": "sv=2023...&sig=MTW_TOKEN_HERE"
}
}
}
XYZ Instance (appsettings.json):
{
"InputFileStorage": {
"ContainerName": "dwd-input-files-xyz",
"AzureBlob": {
"ServiceUrl": "https://storage.blob.core.windows.net",
"ContainerSasToken": "sv=2023...&sig=XYZ_TOKEN_HERE"
}
}
}
Both instances can use the same published EpanetConsoleCore.exe!
Backward Compatibility
The system still supports local file storage for migration scenarios:
StorageProvider=AzureBlob(1): Uses Azure Blob Storage (requires command-line args)StorageProvider=LocalFileSystem(2): Uses local file system (no Azure config needed)
Important:
- Scenarios using
StorageProvider=AzureBlobwill fail loudly if Azure configuration is not passed via command-line arguments - Scenarios using
StorageProvider=LocalFileSystemwill continue to work without any Azure configuration - There is NO silent fallback to
appsettings.json- this is intentional to prevent configuration mistakes
References
- Azure Storage SAS Documentation: https://learn.microsoft.com/en-us/azure/storage/common/storage-sas-overview
- Azure Blob Storage Client Library: https://learn.microsoft.com/en-us/dotnet/api/azure.storage.blobs