This section covers diagnosing and resolving common DICOM problems.
Association Failures
Diagnostic Tool
public class DicomTroubleshooter
{
public void DiagnoseAssociationFailure(string host, int port, string aeTitle)
{
Console.WriteLine("=== DICOM Association Diagnostics ===\n");
// 1. Test network connectivity
Console.WriteLine("1. Testing TCP/IP connectivity...");
if (!TestTcpConnection(host, port))
{
Console.WriteLine(" FAILED: Cannot establish TCP connection");
Console.WriteLine(" Check:");
Console.WriteLine(" - Firewall settings");
Console.WriteLine(" - Network connectivity (ping host)");
Console.WriteLine(" - Correct host address and port");
Console.WriteLine(" - VPN/network routing");
return;
}
Console.WriteLine(" PASSED: TCP connection successful\n");
// 2. Test DICOM association
Console.WriteLine("2. Testing DICOM association...");
DicomAssociation association = new DicomAssociation
{
CallingAETitle = "DIAG_SCU",
CalledAETitle = aeTitle,
Host = host,
Port = port
};
association.AddPresentationContext(
DicomUID.VerificationSOPClass,
DicomTransferSyntax.ExplicitVRLittleEndian
);
try
{
association.Open();
Console.WriteLine(" PASSED: Association established\n");
// 3. Check presentation contexts
Console.WriteLine("3. Checking presentation contexts...");
CheckPresentationContexts(association);
// 4. Test C-ECHO
Console.WriteLine("\n4. Testing C-ECHO...");
TestEcho(association);
association.Close();
}
catch (DicomNetworkException ex)
{
Console.WriteLine($" FAILED: {ex.Message}\n");
ProvideFailureGuidance(ex.Message, aeTitle);
}
}
private bool TestTcpConnection(string host, int port)
{
try
{
using (var client = new System.Net.Sockets.TcpClient())
{
var result = client.BeginConnect(host, port, null, null);
bool success = result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(5));
if (success) client.EndConnect(result);
return success;
}
}
catch
{
return false;
}
}
private void CheckPresentationContexts(DicomAssociation association)
{
foreach (PresentationContext pc in association.PresentationContexts)
{
string status = pc.Result == PresentationContextResult.Accept
? "Accepted" : "Rejected";
Console.WriteLine($" {status}:");
Console.WriteLine($" SOP Class: {GetSOPClassName(pc.AbstractSyntax)}");
Console.WriteLine($" Transfer Syntax: {GetTransferSyntaxName(pc.SelectedTransferSyntax)}");
if (pc.Result != PresentationContextResult.Accept)
{
Console.WriteLine($" Reason: {pc.Result}");
}
}
}
private void TestEcho(DicomAssociation association)
{
try
{
DicomCommandSet request = new DicomCommandSet(DicomCommandType.C_ECHO_RQ);
request.AffectedSOPClassUID = DicomUID.VerificationSOPClass;
request.MessageID = 1;
DicomCommandSet response = association.SendRequest(request, null);
if (response.Status == 0)
{
Console.WriteLine(" PASSED: C-ECHO successful");
}
else
{
Console.WriteLine($" FAILED: C-ECHO returned status 0x{response.Status:X4}");
}
}
catch (Exception ex)
{
Console.WriteLine($" FAILED: {ex.Message}");
}
}
private void ProvideFailureGuidance(string errorMessage, string aeTitle)
{
if (errorMessage.Contains("Called AE") || errorMessage.Contains("AE Title"))
{
Console.WriteLine(" Check:");
Console.WriteLine($" - Called AE Title '{aeTitle}' is correct");
Console.WriteLine(" - AE Title is configured on remote system");
Console.WriteLine(" - AE Title is case-sensitive");
Console.WriteLine(" - No extra spaces in AE Title");
}
else if (errorMessage.Contains("timeout"))
{
Console.WriteLine(" Check:");
Console.WriteLine(" - Remote server is running");
Console.WriteLine(" - Network latency issues");
Console.WriteLine(" - Server is not overloaded");
Console.WriteLine(" - Increase timeout values");
}
else if (errorMessage.Contains("rejected"))
{
Console.WriteLine(" Check:");
Console.WriteLine(" - Calling AE Title is authorized");
Console.WriteLine(" - IP address is in whitelist");
Console.WriteLine(" - Presentation context is supported");
}
}
private string GetSOPClassName(string uid)
{
return uid switch
{
"1.2.840.10008.5.1.4.1.1.2" => "CT Image Storage",
"1.2.840.10008.5.1.4.1.1.4" => "MR Image Storage",
"1.2.840.10008.5.1.4.1.1.7" => "Secondary Capture",
"1.2.840.10008.1.1" => "Verification SOP Class",
_ => uid
};
}
private string GetTransferSyntaxName(string uid)
{
return uid switch
{
"1.2.840.10008.1.2" => "Implicit VR Little Endian",
"1.2.840.10008.1.2.1" => "Explicit VR Little Endian",
"1.2.840.10008.1.2.4.70" => "JPEG Lossless",
"1.2.840.10008.1.2.4.90" => "JPEG 2000 Lossless",
_ => uid
};
}
}
Storage Failures
Storage Diagnostic Tool
public void DiagnoseStorageFailure(string filePath)
{
Console.WriteLine("=== DICOM Storage Diagnostics ===\n");
if (!File.Exists(filePath))
{
Console.WriteLine($"File not found: {filePath}");
return;
}
try
{
DicomDataSet dataset = new DicomDataSet();
dataset.Read(filePath);
Console.WriteLine("File read successfully\n");
// Check required tags
Console.WriteLine("1. Checking required tags...");
CheckRequiredTags(dataset);
// Check UID validity
Console.WriteLine("\n2. Checking UID validity...");
CheckUIDValidity(dataset);
// Check pixel data
if (dataset.Contains(DicomTag.PixelData))
{
Console.WriteLine("\n3. Checking pixel data...");
CheckPixelData(dataset);
}
// Check transfer syntax
Console.WriteLine("\n4. Checking transfer syntax...");
CheckTransferSyntax(dataset);
}
catch (Exception ex)
{
Console.WriteLine($"Error reading file: {ex.Message}");
}
}
private void CheckRequiredTags(DicomDataSet dataset)
{
var requiredTags = new Dictionary<string, string>
{
{ DicomTag.SOPClassUID, "SOP Class UID" },
{ DicomTag.SOPInstanceUID, "SOP Instance UID" },
{ DicomTag.StudyInstanceUID, "Study Instance UID" },
{ DicomTag.SeriesInstanceUID, "Series Instance UID" },
{ DicomTag.PatientName, "Patient Name" },
{ DicomTag.PatientID, "Patient ID" },
{ DicomTag.Modality, "Modality" }
};
bool allPresent = true;
foreach (var tag in requiredTags)
{
if (!dataset.Contains(tag.Key) ||
string.IsNullOrEmpty(dataset[tag.Key]?.Value?.ToString()))
{
Console.WriteLine($" MISSING: {tag.Value} ({tag.Key})");
allPresent = false;
}
else
{
Console.WriteLine($" Present: {tag.Value}");
}
}
if (!allPresent)
{
Console.WriteLine("\n Fix: Ensure all Type 1 and Type 2 tags are present");
}
}
private void CheckUIDValidity(DicomDataSet dataset)
{
var uidTags = new[]
{
DicomTag.SOPClassUID,
DicomTag.SOPInstanceUID,
DicomTag.StudyInstanceUID,
DicomTag.SeriesInstanceUID
};
foreach (var tag in uidTags)
{
if (dataset.Contains(tag))
{
string uid = dataset[tag]?.Value as string;
if (IsValidUID(uid))
{
Console.WriteLine($" Valid: {tag}");
}
else
{
Console.WriteLine($" Invalid: {tag} = '{uid}'");
Console.WriteLine($" UIDs must contain only digits and dots");
}
}
}
}
private bool IsValidUID(string uid)
{
if (string.IsNullOrEmpty(uid)) return false;
return System.Text.RegularExpressions.Regex.IsMatch(uid, @"^[\d.]+$") &&
uid.Length <= 64;
}
private void CheckPixelData(DicomDataSet dataset)
{
try
{
int rows = int.Parse(dataset[DicomTag.Rows]?.Value as string ?? "0");
int cols = int.Parse(dataset[DicomTag.Columns]?.Value as string ?? "0");
int bitsAllocated = int.Parse(dataset[DicomTag.BitsAllocated]?.Value as string ?? "0");
int samplesPerPixel = int.Parse(dataset[DicomTag.SamplesPerPixel]?.Value as string ?? "1");
long expectedSize = (long)rows * cols * (bitsAllocated / 8) * samplesPerPixel;
object pixelData = dataset[DicomTag.PixelData]?.Value;
long actualSize = 0;
if (pixelData is byte[] byteArray)
actualSize = byteArray.Length;
else if (pixelData is short[] shortArray)
actualSize = shortArray.Length * 2;
Console.WriteLine($" Image: {cols}x{rows}");
Console.WriteLine($" Bits Allocated: {bitsAllocated}");
Console.WriteLine($" Expected size: {expectedSize} bytes");
Console.WriteLine($" Actual size: {actualSize} bytes");
if (actualSize == expectedSize)
Console.WriteLine($" Pixel data size is correct");
else if (actualSize == 0)
Console.WriteLine($" Pixel data is missing");
else
Console.WriteLine($" Size mismatch - may be compressed");
}
catch (Exception ex)
{
Console.WriteLine($" Error: {ex.Message}");
}
}
private void CheckTransferSyntax(DicomDataSet dataset)
{
string transferSyntax = dataset.TransferSyntaxUID;
string tsName = GetTransferSyntaxName(transferSyntax);
Console.WriteLine($" Transfer Syntax: {tsName}");
Console.WriteLine($" UID: {transferSyntax}");
if (transferSyntax == "1.2.840.10008.1.2" ||
transferSyntax == "1.2.840.10008.1.2.1" ||
transferSyntax == "1.2.840.10008.1.2.2")
{
Console.WriteLine($" Uncompressed format (widely supported)");
}
else
{
Console.WriteLine($" Compressed format (verify receiver supports this)");
}
}
Transfer Syntax Conversion
public class TransferSyntaxHelper
{
public void ConvertTransferSyntax(
string inputFile, string outputFile, string targetTransferSyntax)
{
Console.WriteLine($"Converting transfer syntax...");
DicomDataSet ds = new DicomDataSet();
ds.Read(inputFile);
string originalTS = ds.TransferSyntaxUID;
Console.WriteLine($"Original: {GetTransferSyntaxName(originalTS)}");
Console.WriteLine($"Target: {GetTransferSyntaxName(targetTransferSyntax)}");
try
{
ds.Write(outputFile, targetTransferSyntax);
Console.WriteLine("Conversion successful");
long originalSize = new FileInfo(inputFile).Length;
long newSize = new FileInfo(outputFile).Length;
Console.WriteLine($"Original: {originalSize / 1024} KB");
Console.WriteLine($"New: {newSize / 1024} KB");
}
catch (Exception ex)
{
Console.WriteLine($"Conversion failed: {ex.Message}");
Console.WriteLine("Attempting decompression approach...");
DecompressAndRecompress(ds, outputFile, targetTransferSyntax);
}
}
private void DecompressAndRecompress(
DicomDataSet ds, string outputFile, string targetTransferSyntax)
{
try
{
// First decompress to uncompressed format
string tempFile = Path.GetTempFileName();
ds.Write(tempFile, DicomTransferSyntax.ExplicitVRLittleEndian);
// Read uncompressed version
DicomDataSet uncompressed = new DicomDataSet();
uncompressed.Read(tempFile);
// Write with target transfer syntax
uncompressed.Write(outputFile, targetTransferSyntax);
File.Delete(tempFile);
Console.WriteLine("Conversion successful via decompression");
}
catch (Exception ex)
{
Console.WriteLine($"Alternative approach failed: {ex.Message}");
}
}
private string GetTransferSyntaxName(string uid)
{
return uid switch
{
"1.2.840.10008.1.2" => "Implicit VR Little Endian",
"1.2.840.10008.1.2.1" => "Explicit VR Little Endian",
"1.2.840.10008.1.2.4.70" => "JPEG Lossless",
"1.2.840.10008.1.2.4.90" => "JPEG 2000 Lossless",
"1.2.840.10008.1.2.4.91" => "JPEG 2000 Lossy",
"1.2.840.10008.1.2.5" => "RLE Lossless",
_ => uid
};
}
}
Common Error Codes
| Status | Name | Description | Action |
|---|---|---|---|
| 0x0000 | Success | Operation completed | None needed |
| 0x0122 | SOP Class Not Supported | SCP doesn’t support this SOP Class | Check SCP capabilities |
| 0xA700 | Out of Resources | SCP cannot store (disk full, etc.) | Check server resources |
| 0xA900 | Data Set Mismatch | Data doesn’t match SOP Class | Validate DICOM file |
| 0xC000 | Cannot Understand | Unable to process request | Check request format |
| 0xFF00 | Pending | More results coming | Continue receiving |
Systematic troubleshooting helps quickly identify and resolve DICOM issues.