Skip to main content

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:โ€‹

IDNameBlobNameUploadedActive
1Main NetworkMain Network-20251021-143022.inp2025-10-21 14:30โŒ
2Main NetworkMain Network-20251022-091540.inp2025-10-22 09:15โŒ
3Main NetworkMain Network-20251023-154500.inp2025-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:โ€‹

  1. User uploads v1 โ†’ DB ID=1, active
  2. User uploads v2 with same name โ†’ DB ID=2, active
  3. User deactivates ID=1 (soft delete) โ†’ Only v2 visible in UI
  4. Scenarios can reference either version by ID
  5. Old versions remain in storage for audit/recovery

๐Ÿ”‘ Key Design Principlesโ€‹

Separation of Concerns:โ€‹

  1. Name (Database) = User-facing display name

    • What users see in the UI
    • Can be duplicated (multiple versions)
    • Searchable, sortable
  2. BlobName (Database) = Unique storage identifier

    • How file is stored on disk/blob
    • Guaranteed unique (database constraint)
    • Never changes after creation
  3. 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

  • _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