DICOM Router - Configuration Reference

Configuration Reference

Overview

The DICOM Proxy uses a multi-layered configuration system based on JSON files and runtime settings. This document provides comprehensive reference for all configuration options.

Configuration Files

Primary Configuration Files

  • appsettings.json - Main application configuration
  • servers.json - External PACS servers configuration
  • nlog.config - Logging configuration (XML)
  • certificate.pfx - SSL/TLS certificate (optional)
  • dicomtls.pfx - DICOM TLS certificate (optional)

Configuration Loading Order

  1. Default values (hardcoded)
  2. appsettings.json
  3. Environment-specific overrides (appsettings.{Environment}.json)
  4. Environment variables
  5. Command-line arguments
  6. Runtime database settings

Main Configuration (appsettings.json)

Complete Configuration Example

{
  "DicomPort": 11112,
  "HttpPort": 8080,
  "HttpsPort": 8443,
  "StoragePath": "C:\\DicomStorage",
  "DatabasePath": "C:\\DicomStorage\\dicom.db",
  "TempPath": "C:\\DicomStorage\\temp",
  "LogPath": "C:\\DicomStorage\\logs",
  "ConfigPath": "C:\\DicomStorage\\config",
  
  "ThisModality": {
    "AE_Title": "DICOMPROXY",
    "Port": 11112,
    "IPAddress": "0.0.0.0",
    "MaxConnections": 50,
    "MaxPDULength": 16384,
    "RequestTimeout": 30000,
    "IdleTimeout": 300000,
    "EnableCompression": true
  },

  "Security": {
    "EnableTLS": false,
    "CertificatePath": "certificate.pfx",
    "CertificatePassword": "",
    "RequireClientCertificate": false,
    "EnableDicomTLS": false,
    "DicomTLSCertPath": "dicomtls.pfx",
    "RequireAuthentication": false,
    "AllowedAETitles": [],
    "BlockedAETitles": [],
    "EnableAuditLogging": true
  },

  "Storage": {
    "MaxStorageSizeGB": 1000,
    "CleanupEnabled": true,
    "CleanupIntervalHours": 24,
    "RetentionDays": 365,
    "MaxConcurrentWrites": 10,
    "UseAsyncIO": true,
    "BufferSizeKB": 64,
    "EnableCompression": false,
    "CompressionLevel": 6,
    "ValidateStoredFiles": true
  },

  "Database": {
    "ConnectionString": "",
    "MaxConnections": 20,
    "CommandTimeoutSeconds": 60,
    "EnableWAL": true,
    "CacheSize": 10000,
    "TempStore": "memory",
    "JournalMode": "wal",
    "Synchronous": "normal"
  },

  "Performance": {
    "MaxConcurrentConnections": 100,
    "ConnectionPoolSize": 50,
    "RequestTimeoutSeconds": 300,
    "MaxMemoryUsageMB": 4096,
    "EnableCaching": true,
    "CacheExpirationMinutes": 30,
    "ThreadPoolMinThreads": 10,
    "ThreadPoolMaxThreads": 100,
    "GCMode": "server"
  },

  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "DicomProxyCore": "Information",
      "FellowOakDicom": "Warning",
      "Microsoft": "Warning"
    },
    "EnableFileLogging": true,
    "EnableConsoleLogging": true,
    "MaxLogFileSizeMB": 100,
    "MaxLogFiles": 10,
    "IncludeScopes": true,
    "EnableStructuredLogging": true
  },

  "Proxy": {
    "EnableProxy": true,
    "DefaultServer": "primary_pacs",
    "LoadBalancingMode": "RoundRobin",
    "FailoverEnabled": true,
    "HealthCheckIntervalSeconds": 60,
    "RetryAttempts": 3,
    "RetryDelaySeconds": 5,
    "EnableConnectionPooling": true,
    "MaxConnectionsPerServer": 10
  },

  "Api": {
    "EnableOpenApi": true,
    "EnableCors": true,
    "AllowedOrigins": ["*"],
    "EnableRateLimiting": true,
    "RateLimitRequestsPerHour": 1000,
    "MaxRequestSizeMB": 100,
    "EnableCompression": true,
    "RequestTimeoutSeconds": 300
  },

  "Features": {
    "EnableQIDORS": true,
    "EnableWADORS": true,
    "EnableSTOWRS": true,
    "EnableDicomWeb": true,
    "EnableImageRendering": true,
    "EnableScripting": false,
    "EnableMDNS": true,
    "EnableWebRTC": false,
    "EnableTUS": true
  },

  "Licensing": {
    "LicenseFile": "dicomproxy.lic",
    "LicenseServer": "https://license.dicom.link",
    "AutoRenewal": true,
    "DemoMode": true,
    "DemoExpirationDays": 30,
    "MaxStudiesInDemo": 100
  },

  "Monitoring": {
    "EnableMetrics": true,
    "MetricsPort": 9090,
    "EnableHealthChecks": true,
    "HealthCheckPort": 8081,
    "EnablePerformanceCounters": true,
    "StatisticsUpdateIntervalSeconds": 60
  }
}

Configuration Sections Reference

DicomPort

  • Type: integer
  • Default: 11112
  • Description: Port for DICOM SCP listener
  • Valid Range: 1024-65535

HttpPort / HttpsPort

  • Type: integer
  • Default: 8080 / 8443
  • Description: Ports for HTTP/HTTPS REST API
  • Valid Range: 1024-65535

StoragePath

  • Type: string
  • Default: .\Storage
  • Description: Root directory for DICOM file storage
  • Requirements: Must be writable, preferably on fast storage

ThisModality Section

Configuration for the local DICOM modality.

{
  "ThisModality": {
    "AE_Title": "DICOMPROXY",
    "Port": 11112,
    "IPAddress": "0.0.0.0",
    "MaxConnections": 50,
    "MaxPDULength": 16384,
    "RequestTimeout": 30000,
    "IdleTimeout": 300000,
    "EnableCompression": true
  }
}
Parameter Type Default Description
AE_Title string “DICOMPROXY” Application Entity title
Port integer 11112 DICOM listener port
IPAddress string “0.0.0.0” Bind IP address (0.0.0.0 = all interfaces)
MaxConnections integer 50 Maximum concurrent DICOM connections
MaxPDULength integer 16384 Maximum PDU length in bytes
RequestTimeout integer 30000 Request timeout in milliseconds
IdleTimeout integer 300000 Idle connection timeout in milliseconds
EnableCompression boolean true Enable DICOM compression

Security Section

{
  "Security": {
    "EnableTLS": false,
    "CertificatePath": "certificate.pfx",
    "CertificatePassword": "",
    "RequireClientCertificate": false,
    "EnableDicomTLS": false,
    "DicomTLSCertPath": "dicomtls.pfx",
    "RequireAuthentication": false,
    "AllowedAETitles": [],
    "BlockedAETitles": [],
    "EnableAuditLogging": true
  }
}
Parameter Type Default Description
EnableTLS boolean false Enable HTTPS for REST API
CertificatePath string “” Path to SSL certificate file
CertificatePassword string “” Certificate password
RequireClientCertificate boolean false Require client certificates
EnableDicomTLS boolean false Enable secure DICOM communications
DicomTLSCertPath string “” Path to DICOM TLS certificate
RequireAuthentication boolean false Require API authentication
AllowedAETitles array [] Whitelist of allowed AE titles (empty = allow all)
BlockedAETitles array [] Blacklist of blocked AE titles
EnableAuditLogging boolean true Enable security audit logging

Storage Section

{
  "Storage": {
    "MaxStorageSizeGB": 1000,
    "CleanupEnabled": true,
    "CleanupIntervalHours": 24,
    "RetentionDays": 365,
    "MaxConcurrentWrites": 10,
    "UseAsyncIO": true,
    "BufferSizeKB": 64,
    "EnableCompression": false,
    "CompressionLevel": 6,
    "ValidateStoredFiles": true
  }
}
Parameter Type Default Description
MaxStorageSizeGB integer 1000 Maximum storage size in GB
CleanupEnabled boolean true Enable automatic cleanup
CleanupIntervalHours integer 24 Cleanup interval in hours
RetentionDays integer 365 File retention period in days
MaxConcurrentWrites integer 10 Maximum concurrent file writes
UseAsyncIO boolean true Use asynchronous I/O operations
BufferSizeKB integer 64 File I/O buffer size in KB
EnableCompression boolean false Enable file compression
CompressionLevel integer 6 Compression level (1-9)
ValidateStoredFiles boolean true Validate files after storage

Performance Section

{
  "Performance": {
    "MaxConcurrentConnections": 100,
    "ConnectionPoolSize": 50,
    "RequestTimeoutSeconds": 300,
    "MaxMemoryUsageMB": 4096,
    "EnableCaching": true,
    "CacheExpirationMinutes": 30,
    "ThreadPoolMinThreads": 10,
    "ThreadPoolMaxThreads": 100,
    "GCMode": "server"
  }
}
Parameter Type Default Description
MaxConcurrentConnections integer 100 Maximum concurrent connections
ConnectionPoolSize integer 50 Connection pool size
RequestTimeoutSeconds integer 300 Request timeout in seconds
MaxMemoryUsageMB integer 4096 Maximum memory usage in MB
EnableCaching boolean true Enable response caching
CacheExpirationMinutes integer 30 Cache expiration time
ThreadPoolMinThreads integer 10 Minimum thread pool threads
ThreadPoolMaxThreads integer 100 Maximum thread pool threads
GCMode string “server” Garbage collection mode

PACS Servers Configuration (servers.json)

{
  "servers": [
    {
      "id": "primary_pacs",
      "name": "Primary PACS Server",
      "ae_title": "PRIMARYPACS",
      "hostname": "192.168.1.100",
      "port": 11112,
      "enabled": true,
      "priority": 1,
      "max_connections": 20,
      "timeout_seconds": 30,
      "retry_attempts": 3,
      "retry_delay_seconds": 5,
      "health_check_enabled": true,
      "health_check_interval_seconds": 60,
      "supported_services": ["C-STORE", "C-FIND", "C-GET", "C-MOVE", "C-ECHO"],
      "transfer_syntaxes": [
        "1.2.840.10008.1.2",
        "1.2.840.10008.1.2.1",
        "1.2.840.10008.1.2.4.50"
      ],
      "compression_enabled": true,
      "tls_enabled": false,
      "tls_certificate_path": "",
      "description": "Main production PACS server",
      "tags": ["production", "primary", "ct", "mr"],
      "routing_rules": {
        "modality_filter": ["CT", "MR", "US"],
        "time_based_routing": {
          "enabled": false,
          "business_hours_only": false,
          "time_zone": "UTC"
        }
      },
      "load_balancing": {
        "weight": 100,
        "max_requests_per_second": 50,
        "circuit_breaker_enabled": true,
        "failure_threshold": 5,
        "recovery_timeout_seconds": 300
      },
      "storage_mapping": {
        "local_storage_enabled": true,
        "forward_to_server": true,
        "duplicate_handling": "skip"
      },
      "authentication": {
        "require_mutual_tls": false,
        "trusted_certificates": []
      },
      "custom_properties": {
        "institution": "General Hospital",
        "department": "Radiology",
        "vendor": "Vendor A",
        "version": "5.2.1"
      }
    },
    {
      "id": "archive_pacs",
      "name": "Archive PACS Server",
      "ae_title": "ARCHIVEPACS",
      "hostname": "192.168.1.101",
      "port": 11112,
      "enabled": true,
      "priority": 2,
      "max_connections": 10,
      "timeout_seconds": 60,
      "retry_attempts": 3,
      "retry_delay_seconds": 10,
      "health_check_enabled": true,
      "health_check_interval_seconds": 120,
      "supported_services": ["C-STORE", "C-FIND", "C-GET", "C-ECHO"],
      "transfer_syntaxes": [
        "1.2.840.10008.1.2",
        "1.2.840.10008.1.2.4.90"
      ],
      "compression_enabled": true,
      "tls_enabled": false,
      "description": "Long-term archive storage",
      "tags": ["archive", "secondary", "long-term"],
      "routing_rules": {
        "modality_filter": [],
        "time_based_routing": {
          "enabled": true,
          "business_hours_only": false,
          "time_zone": "UTC"
        }
      },
      "load_balancing": {
        "weight": 50,
        "max_requests_per_second": 20,
        "circuit_breaker_enabled": true,
        "failure_threshold": 3,
        "recovery_timeout_seconds": 600
      },
      "storage_mapping": {
        "local_storage_enabled": false,
        "forward_to_server": true,
        "duplicate_handling": "overwrite"
      }
    }
  ],
  "global_settings": {
    "default_timeout_seconds": 30,
    "default_retry_attempts": 3,
    "default_max_connections": 10,
    "health_check_enabled": true,
    "load_balancing_mode": "weighted_round_robin",
    "failover_enabled": true,
    "connection_pooling_enabled": true
  }
}

Server Configuration Parameters

Parameter Type Required Description
id string Yes Unique server identifier
name string Yes Human-readable server name
ae_title string Yes DICOM Application Entity title
hostname string Yes Server hostname or IP address
port integer Yes DICOM port number
enabled boolean No Enable/disable server
priority integer No Server priority for routing (1=highest)
max_connections integer No Maximum concurrent connections
timeout_seconds integer No Connection timeout
supported_services array No Supported DICOM services
transfer_syntaxes array No Supported transfer syntaxes

Environment Variables

Override configuration values using environment variables:

# Basic settings
DICOMPROXY_DicomPort=11112
DICOMPROXY_HttpPort=8080
DICOMPROXY_StoragePath=D:\DicomStorage

# Nested settings (use double underscores)
DICOMPROXY_ThisModality__AE_Title=MYPROXY
DICOMPROXY_Security__EnableTLS=true
DICOMPROXY_Performance__MaxMemoryUsageMB=8192

# Array values (use colon separator)
DICOMPROXY_Security__AllowedAETitles=CLIENT1:CLIENT2:CLIENT3

Command Line Arguments

Override configuration via command line:

DicomProxyRTWindows.exe --DicomPort 11113 --HttpPort 8081 --StoragePath "D:\CustomStorage"

# Nested parameters
DicomProxyRTWindows.exe --ThisModality:AE_Title "CUSTOMPROXY" --Security:EnableTLS true

# Help
DicomProxyRTWindows.exe --help

Logging Configuration (nlog.config)

<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

  <variable name="logDirectory" value="C:\DicomStorage\logs"/>
  
  <targets>
    <!-- File targets -->
    <target xsi:type="File" name="allFile"
            fileName="${logDirectory}\dicom-proxy-${shortdate}.log"
            layout="${longdate} ${uppercase:${level}} ${logger} ${message} ${exception:format=tostring}"
            maxArchiveFiles="10"
            archiveAboveSize="104857600" />

    <target xsi:type="File" name="errorFile"
            fileName="${logDirectory}\errors-${shortdate}.log"
            layout="${longdate} ${uppercase:${level}} ${logger} ${message} ${exception:format=tostring}"
            maxArchiveFiles="10"
            archiveAboveSize="104857600" />

    <target xsi:type="File" name="dicomFile"
            fileName="${logDirectory}\dicom-operations-${shortdate}.log"
            layout="${longdate} [${level}] ${logger} ${message}"
            maxArchiveFiles="30"
            archiveAboveSize="52428800" />

    <!-- Console target -->
    <target xsi:type="Console" name="console"
            layout="${time} [${level:uppercase=true}] ${logger:shortName=true}: ${message} ${exception:format=shorttype}" />

    <!-- Structured logging target -->
    <target xsi:type="File" name="jsonFile"
            fileName="${logDirectory}\structured-${shortdate}.json">
      <layout xsi:type="JsonLayout">
        <attribute name="timestamp" layout="${date:format=o}" />
        <attribute name="level" layout="${level}" />
        <attribute name="logger" layout="${logger}" />
        <attribute name="message" layout="${message}" />
        <attribute name="exception" layout="${exception:format=@}" />
        <attribute name="properties" encode="false">
          <layout xsi:type="JsonLayout" includeAllProperties="true" maxRecursionLimit="2" />
        </attribute>
      </layout>
    </target>

    <!-- Database target (optional) -->
    <target xsi:type="Database" name="database"
            connectionString="Data Source=C:\DicomStorage\logs.db"
            commandText="INSERT INTO Logs(Timestamp,Level,Logger,Message,Exception) VALUES(@timestamp,@level,@logger,@message,@exception)">
      <parameter name="@timestamp" layout="${date}" />
      <parameter name="@level" layout="${level}" />
      <parameter name="@logger" layout="${logger}" />
      <parameter name="@message" layout="${message}" />
      <parameter name="@exception" layout="${exception}" />
    </target>
  </targets>

  <rules>
    <!-- Application logs -->
    <logger name="DicomProxyCore.*" minlevel="Info" writeTo="allFile,console" />
    <logger name="DicomProxyCore.CStoreSCP.*" minlevel="Info" writeTo="dicomFile" />
    
    <!-- Error logs -->
    <logger name="*" minlevel="Error" writeTo="errorFile" />
    
    <!-- Structured logs -->
    <logger name="*" minlevel="Info" writeTo="jsonFile" />
    
    <!-- Third-party libraries -->
    <logger name="FellowOakDicom.*" minlevel="Warn" writeTo="allFile" />
    <logger name="Microsoft.*" minlevel="Warn" writeTo="allFile" />
    <logger name="System.*" minlevel="Warn" writeTo="allFile" />
    
    <!-- Suppress noisy loggers -->
    <logger name="Microsoft.AspNetCore.*" maxlevel="Info" final="true" />
  </rules>
</nlog>

Configuration Validation

Schema Validation

The application validates configuration on startup. Common validation errors:

{
  "errors": [
    {
      "property": "DicomPort",
      "message": "Port must be between 1024 and 65535",
      "value": 80
    },
    {
      "property": "StoragePath",
      "message": "Storage path is not writable",
      "value": "C:\\ReadOnlyFolder"
    },
    {
      "property": "ThisModality.AE_Title",
      "message": "AE Title must be 1-16 characters, alphanumeric only",
      "value": "Invalid-AE-Title-Too-Long"
    }
  ]
}

Runtime Validation Script

# validate_config.ps1
param([string]$ConfigPath = "appsettings.json")

function Test-DicomProxyConfig {
    param($ConfigFile)
    
    if (!(Test-Path $ConfigFile)) {
        Write-Error "Configuration file not found: $ConfigFile"
        return $false
    }
    
    try {
        $config = Get-Content $ConfigFile | ConvertFrom-Json
        $isValid = $true
        
        # Validate ports
        $ports = @($config.DicomPort, $config.HttpPort, $config.HttpsPort)
        foreach ($port in $ports) {
            if ($port -lt 1024 -or $port -gt 65535) {
                Write-Warning "Invalid port: $port (must be 1024-65535)"
                $isValid = $false
            }
        }
        
        # Validate storage path
        if ($config.StoragePath) {
            $parentPath = Split-Path $config.StoragePath -Parent
            if (!(Test-Path $parentPath)) {
                Write-Warning "Storage parent path does not exist: $parentPath"
                $isValid = $false
            }
        }
        
        # Validate AE Title
        $aeTitle = $config.ThisModality.AE_Title
        if ($aeTitle.Length -gt 16 -or $aeTitle -notmatch '^[A-Z0-9]+$') {
            Write-Warning "Invalid AE Title: $aeTitle (must be 1-16 alphanumeric characters)"
            $isValid = $false
        }
        
        if ($isValid) {
            Write-Host "Configuration validation passed" -ForegroundColor Green
        } else {
            Write-Host "Configuration validation failed" -ForegroundColor Red
        }
        
        return $isValid
    }
    catch {
        Write-Error "Configuration parsing error: $($_.Exception.Message)"
        return $false
    }
}

Test-DicomProxyConfig -ConfigFile $ConfigPath

Configuration Templates

Minimal Configuration

{
  "DicomPort": 11112,
  "HttpPort": 8080,
  "StoragePath": "C:\\DicomStorage",
  "ThisModality": {
    "AE_Title": "DICOMPROXY"
  }
}

Development Configuration

{
  "DicomPort": 11112,
  "HttpPort": 8080,
  "StoragePath": "C:\\DicomStorage",
  "ThisModality": {
    "AE_Title": "DEVPROXY",
    "MaxConnections": 10
  },
  "Logging": {
    "LogLevel": {
      "Default": "Debug",
      "DicomProxyCore": "Debug"
    }
  },
  "Features": {
    "EnableScripting": true
  }
}

Production Configuration

{
  "DicomPort": 11112,
  "HttpPort": 8080,
  "HttpsPort": 8443,
  "StoragePath": "D:\\DicomStorage",
  "ThisModality": {
    "AE_Title": "PRODPROXY",
    "MaxConnections": 100
  },
  "Security": {
    "EnableTLS": true,
    "CertificatePath": "certificate.pfx",
    "RequireAuthentication": true,
    "EnableAuditLogging": true
  },
  "Performance": {
    "MaxConcurrentConnections": 200,
    "MaxMemoryUsageMB": 8192,
    "EnableCaching": true
  },
  "Storage": {
    "MaxStorageSizeGB": 5000,
    "CleanupEnabled": true,
    "RetentionDays": 2555
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "DicomProxyCore": "Information"
    }
  }
}

This configuration reference provides comprehensive documentation for all configuration options available in the DICOM Proxy system. For specific deployment scenarios, refer to the Installation Guide and Examples & Tutorials.