Input File Naming Strategy
Date: October 21, 2025 Status: โ Implemented
๐ฏ Final Decisionsโ
1. Blob Naming: User Name + Timestampโ
{sanitized-user-name}-{yyyyMMdd-HHmmss}.inp
2. Container Naming: Instance-Level Configurationโ
Configured in appsettings.json (not in database)
๐ How It Worksโ
User Uploads a File:โ
User Input:
- File:
network.inp(original filename - ignored) - Name:
"My Network Model"(display name) - Description:
"Updated hydraulic model"(optional)
System Generates:
Nameโ Stored as-is:"My Network Model"BlobNameโ Generated:"My Network Model-20251021-143022.inp"ContainerNameโ From config:"hydrotrek-inputfiles"
Storage Location:
LocalFileSystem: C:\HydroTrek\InputFiles\hydrotrek-inputfiles\My Network Model-20251021-143022.inp
Azure Blob: https://account.blob.core.windows.net/hydrotrek-inputfiles/My Network Model-20251021-143022.inp
Database Record:
{
"id": 1,
"name": "My Network Model",
"description": "Updated hydraulic model",
"blobName": "My Network Model-20251021-143022.inp",
"storageProvider": 2,
"fileSizeBytes": 245678,
"uploadedAt": "2025-10-21T14:30:22Z"
}
๐ Versioning Exampleโ
Scenario: User Uploads Multiple Versionsโ
Upload 1 (Oct 21, 2:30 PM):
Name: "Main Network"
BlobName: "Main Network-20251021-143022.inp"
ID: 1
Upload 2 (Oct 22, 9:15 AM) - Same display name:
Name: "Main Network"
BlobName: "Main Network-20251022-091540.inp"
ID: 2
Upload 3 (Oct 23, 3:45 PM) - Same display name:
Name: "Main Network"
BlobName: "Main Network-20251023-154500.inp"
ID: 3
Database View:โ
| ID | Name | BlobName | Uploaded | Active |
|---|---|---|---|---|
| 1 | Main Network | Main Network-20251021-143022.inp | 2025-10-21 14:30 | โ |
| 2 | Main Network | Main Network-20251022-091540.inp | 2025-10-22 09:15 | โ |
| 3 | Main Network | Main Network-20251023-154500.inp | 2025-10-23 15:45 | โ |
Storage View:โ
hydrotrek-inputfiles/
โโโ Main Network-20251021-143022.inp (215 KB)
โโโ Main Network-20251022-091540.inp (218 KB)
โโโ Main Network-20251023-154500.inp (220 KB)
User Workflow:โ
- User uploads v1 โ DB ID=1, active
- User uploads v2 with same name โ DB ID=2, active
- User deactivates ID=1 (soft delete) โ Only v2 visible in UI
- Scenarios can reference either version by ID
- Old versions remain in storage for audit/recovery
๐ Key Design Principlesโ
Separation of Concerns:โ
Name(Database) = User-facing display name- What users see in the UI
- Can be duplicated (multiple versions)
- Searchable, sortable
BlobName(Database) = Unique storage identifier- How file is stored on disk/blob
- Guaranteed unique (database constraint)
- Never changes after creation
ContainerName(Configuration) = Instance-specific- Where files are stored (which container/directory)
- Configured per deployment
- Not stored in database
Why This Works:โ
- โ Users think in terms of names ("My Network")
- โ System manages unique identifiers automatically
- โ Timestamps provide natural versioning
- โ No collision handling needed
- โ No user input for container selection
๐ Implementation Detailsโ
Code Location:โ
dwd-api-aspnet/DwdApiAspNet/Controllers/InputFileController.cs - Line ~129-133
// Generate unique blob name: {UserName}-{Timestamp}.inp
// This ensures uniqueness while keeping human-readable names
var timestamp = DateTime.UtcNow.ToString("yyyyMMdd-HHmmss");
var sanitizedName = SanitizeFileName(name);
var blobName = $"{sanitizedName}-{timestamp}.inp";
Sanitization:โ
private string SanitizeFileName(string fileName)
{
if (string.IsNullOrWhiteSpace(fileName))
{
return "file";
}
var invalidChars = Path.GetInvalidFileNameChars();
var sanitized = new string(fileName.Select(c =>
invalidChars.Contains(c) ? '_' : c
).ToArray());
return sanitized;
}
Examples:
"My Network!"โ"My Network_""Test/Model"โ"Test_Model""Network:v2"โ"Network_v2"
๐ฏ Benefits of This Approachโ
For Users:โ
- โ Simple upload process (just name + description)
- โ No need to think about versioning
- โ No need to know about containers or blob names
- โ Natural version management (upload again = new version)
For Admins:โ
- โ Easy to identify files in storage browser
- โ Chronological ordering in storage
- โ Audit trail built-in (timestamp)
- โ No collision resolution needed
For Developers:โ
- โ No complex versioning logic
- โ No conflict resolution needed
- โ Guaranteed uniqueness (database constraint + timestamp)
- โ Simple implementation
๐ Alternatives Consideredโ
โ Option 1: Original Filename Onlyโ
network.inp
- Problem: Not unique, multiple uploads would fail
โ Option 2: User Name Onlyโ
My Network Model.inp
- Problem: Still not unique if user uploads same name twice
โ ๏ธ Option 3: User Name + Short GUIDโ
My Network Model-a3f8c912.inp
- Pro: Shorter than timestamp
- Con: Less meaningful for humans
- Why not chosen: Timestamp provides audit trail
โ Option 4: Pure GUIDโ
e7f3c2a1-4b5d-4e8f-9c1a-2d3e4f5a6b7c.inp
- Pro: Guaranteed unique
- Con: Not human-readable, hard to manage
โ Option 5: User Name + Timestamp (CHOSEN)โ
My Network Model-20251021-143022.inp
- Pro: Unique + human-readable + audit trail
- Pro: Natural versioning
- Pro: Sortable by time
- Why chosen: Best balance of uniqueness and readability
๐งช Testing Scenariosโ
Test 1: Upload Same Name Twiceโ
Upload 1: Name="Test" โ BlobName="Test-20251021-100000.inp"
Upload 2: Name="Test" โ BlobName="Test-20251021-100030.inp"
Result: โ
Both files saved successfully
Test 2: Special Characters in Nameโ
Upload: Name="Network/Test:v2!" โ BlobName="Network_Test_v2_-20251021-100000.inp"
Result: โ
Sanitized automatically
Test 3: Rapid Uploads (Same Second)โ
Upload 1: Name="Test" โ BlobName="Test-20251021-143022.inp"
Upload 2: Name="Test" (1 second later) โ BlobName="Test-20251021-143023.inp"
Result: โ
Different timestamps, both unique
Test 4: Empty Nameโ
Upload: Name="" (user doesn't provide name)
Fallback: Uses original filename: "network.inp"
BlobName: "network-20251021-143022.inp"
Result: โ
Still unique with timestamp
๐ Related Documentationโ
_docs/input_file_blob_storage_design.md- Complete blob storage design_docs/remove_container_name_migration.md- Container name removal migration_docs/blob_storage_implementation_plan.md- Implementation phases
โ Summaryโ
What users see:
- Upload form with Name + Description fields
- Table showing user-friendly names
- No technical details about storage
What system manages:
- Unique blob names with timestamps
- Container configuration per instance
- Storage provider abstraction
- Automatic versioning
Result:
- Simple UX + Robust backend
- No naming conflicts
- Natural version management
- Easy to understand and maintain