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.
appsettings.json
- Main application configurationservers.json
- External PACS servers configurationnlog.config
- Logging configuration (XML)certificate.pfx
- SSL/TLS certificate (optional)dicomtls.pfx
- DICOM TLS certificate (optional)appsettings.json
appsettings.{Environment}.json
){
"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
}
}
integer
11112
1024-65535
integer
8080
/ 8443
1024-65535
string
.\Storage
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": {
"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": {
"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": {
"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 |
{
"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
}
}
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 |
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
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
<?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>
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"
}
]
}
# 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
{
"DicomPort": 11112,
"HttpPort": 8080,
"StoragePath": "C:\\DicomStorage",
"ThisModality": {
"AE_Title": "DICOMPROXY"
}
}
{
"DicomPort": 11112,
"HttpPort": 8080,
"StoragePath": "C:\\DicomStorage",
"ThisModality": {
"AE_Title": "DEVPROXY",
"MaxConnections": 10
},
"Logging": {
"LogLevel": {
"Default": "Debug",
"DicomProxyCore": "Debug"
}
},
"Features": {
"EnableScripting": true
}
}
{
"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.