(8/10/2017 6:41:31 PM) Starting C-Store SCP server on port 104
---------------------------------------------------------------------------
(8/10/2017 6:41:44 PM) CStoreSCP Constructor:
(8/10/2017 6:41:44 PM) Remote Host: *REMOVED*
(8/10/2017 6:41:44 PM) Local Host: *REMOVED*:104
(8/10/2017 6:41:44 PM) Association Request Received
(8/10/2017 6:41:44 PM) CalledAE: RESEARCH
(8/10/2017 6:41:44 PM) CallingAE: *REMOVED*
(8/10/2017 6:41:44 PM) Result: Accept
(8/10/2017 6:41:44 PM) Association Response Sent
(8/10/2017 6:41:44 PM) Connection Closed
---------------------------------------------------------------------------
(8/10/2017 6:43:44 PM) CStoreSCP Constructor:
(8/10/2017 6:43:44 PM) Remote Host: *REMOVED*
(8/10/2017 6:43:44 PM) Local Host: *REMOVED*
(8/10/2017 6:43:44 PM) Association Request Received
(8/10/2017 6:43:44 PM) CalledAE: RESEARCH
(8/10/2017 6:43:44 PM) CallingAE: *REMOVED*
(8/10/2017 6:43:44 PM) Result: Accept
(8/10/2017 6:43:45 PM) CStoreRequest Received:
(8/10/2017 6:43:45 PM) AccessionNum: *REMOVED*
(8/10/2017 6:43:45 PM) StudyNum: 1.2.392.200036.9125.2.212190217157136227.64849465321.25086250
(8/10/2017 6:43:45 PM) SeriesNum: 1.2.392.200036.9125.3.212190217157136227.64849465321.25086252
(8/10/2017 6:43:45 PM) InstanceNum: 1.2.392.200036.9125.9.0.420421674.68468436.2648302472
(8/10/2017 6:43:45 PM) CStoreRequest Received:
(8/10/2017 6:43:45 PM) AccessionNum: *REMOVED*
(8/10/2017 6:43:45 PM) StudyNum: 1.2.392.200036.9125.2.212190217157136227.64849465321.25086250
(8/10/2017 6:43:45 PM) SeriesNum: 1.2.392.200036.9125.3.212190217157136227.64849466378.41601774
(8/10/2017 6:43:45 PM) InstanceNum: 1.2.392.200036.9125.9.0.420422698.85507796.2648302472
(8/10/2017 6:43:45 PM) Association Response Sent
(8/10/2017 6:43:45 PM) Connection Closed
-----------------------------------------------------------------
(8/10/2017 6:41:37 PM) Image Retrieval Starting
-----------------------------------------------------------------
_____________________STUDY_____________________
Patient: *REMOVED*
Patient ID: *REMOVED*
Modalities: CR
Study: XR CHEST AP PORTABLE
Study Number: 0
Accession Number: *REMOVED*
Study Instance ID: 1.2.392.200036.9125.2.212190217157136227.64849465321.25086250
Study Date: *REMOVED* 12:00:00 AM
Series Count: 2
Study Find Response Status: Success
_____________________MOVE_____________________
(8/10/2017 6:41:38 PM) Sending Request for Study: 1.2.392.200036.9125.2.212190217157136227.64849465321.25086250
(8/10/2017 6:41:48 PM) Sending is in progress. please wait.. Pending
(8/10/2017 6:41:58 PM) Sending is in progress. please wait.. Pending
(8/10/2017 6:42:08 PM) Sending is in progress. please wait.. Pending
(8/10/2017 6:42:18 PM) Sending is in progress. please wait.. Pending
(8/10/2017 6:42:28 PM) Sending is in progress. please wait.. Pending
(8/10/2017 6:42:38 PM) Sending is in progress. please wait.. Pending
(8/10/2017 6:42:48 PM) Sending is in progress. please wait.. Pending
(8/10/2017 6:42:58 PM) Sending is in progress. please wait.. Pending
(8/10/2017 6:43:08 PM) Sending is in progress. please wait.. Pending
(8/10/2017 6:43:18 PM) Sending is in progress. please wait.. Pending
(8/10/2017 6:43:28 PM) Sending is in progress. please wait.. Pending
(8/10/2017 6:43:38 PM) Sending is in progress. please wait.. Pending
(8/10/2017 6:43:48 PM) Sending is in progress. please wait.. Pending
(8/10/2017 6:43:58 PM) Sending is in progress. please wait.. Pending
(8/10/2017 6:44:08 PM) Sending is in progress. please wait.. Pending
(8/10/2017 6:44:18 PM) Sending is in progress. please wait.. Pending
(8/10/2017 6:44:28 PM) Sending is in progress. please wait.. Pending
(8/10/2017 6:44:38 PM) Sending is in progress. please wait.. Pending
(8/10/2017 6:44:48 PM) Sending is in progress. please wait.. Pending
(8/10/2017 6:44:58 PM) Sending is in progress. please wait.. Pending
(8/10/2017 6:45:08 PM) Sending is in progress. please wait.. Pending
(8/10/2017 6:45:18 PM) Sending is in progress. please wait.. Pending
(8/10/2017 6:45:28 PM) Sending is in progress. please wait.. Pending
(8/10/2017 6:45:38 PM) Sending is in progress. please wait.. Pending
(8/10/2017 6:45:45 PM) Move Success: Success
(8/10/2017 6:45:46 PM) Move Complete for Study ID: 1.2.392.200036.9125.2.212190217157136227.64849465321.25086250
All move requests complete
using System;
using System.IO;
using System.Text;
using Dicom.Log;
using Dicom.Network;
namespace Dicom.CStoreSCP
{
internal class Program
{
private static string StoragePath = @"C:\DICOM\Images";
private static string LogPath = @"C:\DICOM\Log";
private static void Main(string[] args)
{
var dict = DicomDictionary.Default;
var port = 104;
Log($"({DateTime.Now}) Starting C-Store SCP server on port {port} ");
var server = DicomServer.Create<CStoreSCP>(port);
Console.ReadLine();
}
public static void Log(string logMessage)
{
Console.WriteLine(logMessage);
string logFile = Path.Combine(LogPath, DateTime.Now.ToString("yyyyMMdd", System.Globalization.CultureInfo.GetCultureInfo("en-US")) + "_CStoreSCPLog.txt");
using (FileStream logFileStream = new FileStream(logFile, FileMode.Append, FileAccess.Write, FileShare.Write))
{
using (StreamWriter w = new StreamWriter(logFileStream))
{
w.WriteLine(logMessage);
}
}
}
private class CStoreSCP : DicomService, IDicomServiceProvider, IDicomCStoreProvider, IDicomCEchoProvider
{
private static DicomTransferSyntax[] AcceptedTransferSyntaxes = new DicomTransferSyntax[]
{
DicomTransferSyntax.ImplicitVRLittleEndian,
DicomTransferSyntax.ExplicitVRLittleEndian,
DicomTransferSyntax.ExplicitVRBigEndian
};
private static DicomTransferSyntax[] AcceptedImageTransferSyntaxes = new DicomTransferSyntax[]
{
// Uncompressed
DicomTransferSyntax.ImplicitVRLittleEndian,
DicomTransferSyntax.ExplicitVRLittleEndian,
DicomTransferSyntax.ExplicitVRBigEndian,
// Lossless
DicomTransferSyntax.JPEGLSLossless,
DicomTransferSyntax.JPEG2000Lossless,
DicomTransferSyntax.JPEGProcess14SV1,
DicomTransferSyntax.JPEGProcess14,
DicomTransferSyntax.RLELossless,
// Lossy
DicomTransferSyntax.JPEGLSNearLossless,
DicomTransferSyntax.JPEG2000Lossy,
DicomTransferSyntax.JPEGProcess1,
DicomTransferSyntax.JPEGProcess2_4,
};
public CStoreSCP(INetworkStream stream, Encoding fallbackEncoding, Logger log)
: base(stream, fallbackEncoding, log)
{
string logTxt =
$"--------------------------------------------------------------------------- \r\n" +
$"({DateTime.Now}) CStoreSCP Constructor: \r\n" +
$"({DateTime.Now}) Remote Host: {stream.RemoteHost}:{stream.RemotePort} \r\n" +
$"({DateTime.Now}) Local Host: {stream.LocalHost}:{stream.LocalPort}";
Log(logTxt);
}
public void OnReceiveAssociationRequest(DicomAssociation association)
{
string logTxt =
$"({DateTime.Now}) Association Request Received \r\n" +
$"({DateTime.Now}) CalledAE: {association.CalledAE} \r\n" +
$"({DateTime.Now}) CallingAE: {association.CallingAE}";
Log(logTxt);
if (association.CalledAE != "RESEARCH")
{
SendAssociationReject(
DicomRejectResult.Permanent,
DicomRejectSource.ServiceUser,
DicomRejectReason.CalledAENotRecognized);
Log($"({DateTime.Now}) AE Invalid: {association.CalledAE}");
return;
}
foreach (var pc in association.PresentationContexts)
{
if (pc.AbstractSyntax == DicomUID.Verification)
{
pc. AcceptTransferSyntaxes(AcceptedTransferSyntaxes);
}
else if (pc.AbstractSyntax.StorageCategory != DicomStorageCategory.None)
{
pc.AcceptTransferSyntaxes(AcceptedImageTransferSyntaxes);
Log($"({DateTime.Now}) Result: {pc.Result}");
}
}
SendAssociationAccept(association);
}
public void OnReceiveAssociationReleaseRequest()
{
Log($"({DateTime.Now}) Association Response Sent");
SendAssociationReleaseResponse();
}
public void OnReceiveAbort(DicomAbortSource source, DicomAbortReason reason)
{
Log($"({DateTime.Now}) Receive Aborted: {reason.ToString()}");
}
public void OnConnectionClosed(Exception exception)
{
Log($"({DateTime.Now}) Connection Closed");
}
public DicomCStoreResponse OnCStoreRequest(DicomCStoreRequest request)
{
var patientMRN = request.Dataset.Get<string>(DicomTag.PatientID);
var accessionNum = request.Dataset.Get<string>(DicomTag.AccessionNumber);
var studyUid = request.Dataset.Get<string>(DicomTag.StudyInstanceUID);
var seriesUid = request.Dataset.Get<string>(DicomTag.SeriesInstanceUID);
var instanceUid = request.SOPInstanceUID.UID;
string logTxt =
$"({DateTime.Now}) CStoreRequest Received: \r\n" +
$"({DateTime.Now}) AccessionNum: {accessionNum} \r\n" +
$"({DateTime.Now}) StudyNum: {studyUid} \r\n" +
$"({DateTime.Now}) SeriesNum: {seriesUid} \r\n" +
$"({DateTime.Now}) InstanceNum: {instanceUid}";
Log(logTxt);
var path = Path.GetFullPath(Program.StoragePath);
path = Path.Combine(path, patientMRN, accessionNum, studyUid, seriesUid);
if (!Directory.Exists(path)) Directory.CreateDirectory(path);
path = Path.Combine(path, instanceUid) + ".dcm";
request.File.Save(path);
return new DicomCStoreResponse(request, DicomStatus.Success);
}
public void OnCStoreRequestException(string tempFileName, Exception e)
{
Log($"({DateTime.Now}) CStore Request Exception: {e.Message}");
}
public DicomCEchoResponse OnCEchoRequest(DicomCEchoRequest request)
{
Log($"({DateTime.Now}) CEcho Request");
return new DicomCEchoResponse(request, DicomStatus.Success);
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Data;
using Dicom;
using Dicom.Network;
using Dicom.Log;
namespace DICOM_Image_Work
{
internal class Program
{
private static string LogPath = @"C:\apps\DICOM\Log";
private static string ServerHost = "**REMOVED**";
private static int ServerPort = ####;
private static string ServerAET = "**REMOVED**";
private static string LocalAET = "RESEARCH";
private static string AccessionNumber = "62967717";
static void Main(string[] args)
{
Log("-----------------------------------------------------------------");
Log($"({DateTime.Now}) Image Retrieval Starting");
Log("-----------------------------------------------------------------");
FindStudyByAccessionNumber(AccessionNumber);
Console.ReadLine();
}
public static void Log(string logMessage)
{
Console.WriteLine(logMessage);
string logFile = Path.Combine(LogPath, DateTime.Now.ToString("yyyyMMdd", System.Globalization.CultureInfo.GetCultureInfo("en-US")) + "_DicomRequestLog.txt");
using (TextWriter w = File.AppendText(logFile))
{
w.WriteLine(logMessage);
}
}
public static void FindStudyByAccessionNumber(string accessionNumber)
{
var cStudyFindRequest = DicomCFindRequest.CreateStudyQuery(accession: AccessionNumber);
FindStudy(cStudyFindRequest);
}
public static void FindStudyByPatientID(string patientID)
{
var cStudyFindRequest = DicomCFindRequest.CreateStudyQuery(patientId: PatientID);
FindStudy(cStudyFindRequest);
}
public static void FindStudyByPatientName(string patientName)
{
var cStudyFindRequest = DicomCFindRequest.CreateStudyQuery(patientName: PatientName);
FindStudy(cStudyFindRequest);
}
public static void FindStudy(DicomCFindRequest cStudyFindRequest)
{
try
{
DicomClient client = new DicomClient();
client.NegotiateAsyncOps();
Log("_____________________STUDY_____________________ \r\n");
bool? findComplete = null;
List<string> studyUids = new List<string>();
cStudyFindRequest.OnResponseReceived += (DicomCFindRequest study_request, DicomCFindResponse study_response) =>
{
DisplayStudyResponse(study_response);
if (study_response.Status.State == DicomState.Pending)
{
studyUids.Add(study_response.Dataset?.Get<string>(DicomTag.StudyInstanceUID));
findComplete = false;
}
else if (study_response.Status.State == DicomState.Success)
{
findComplete = true;
}
else if (study_response.Status.State == DicomState.Failure)
{
findComplete = true;
}
else if (study_response.Status.State == DicomState.Warning)
{
findComplete = false;
}
else if (study_response.Status.State == DicomState.Cancel)
{
findComplete = true;
}
};
client.AddRequest(cStudyFindRequest);
client.Send(ServerHost, ServerPort, false, LocalAET, ServerAET);
while (findComplete != true)
{
// Log("waiting...waiting....");
}
FindStudySeries(studyUids);
}
catch (Exception ex)
{
Log("Study Find Exception: " + ex.Message + "\r\n");
}
}
public static void DisplayStudyResponse(DicomCFindResponse response)
{
try
{
if (response.Status == DicomStatus.Pending)
{
Log($"Patient: {response.Dataset.Get<string>(DicomTag.PatientName)} \r\n" +
$"Patient ID: {response.Dataset.Get<string>(DicomTag.PatientID)} \r\n" +
$"Modalities: {response.Dataset.Get<string>(DicomTag.ModalitiesInStudy)} \r\n" +
$"Study: {response.Dataset.Get<string>(DicomTag.StudyDescription)} \r\n" +
$"Study Number: {response.Dataset.Get<string>(DicomTag.StudyID)} \r\n" +
$"Accession Number: {response.Dataset.Get<string>(DicomTag.AccessionNumber)} \r\n" +
$"Study Instance ID: {response.Dataset.Get<string>(DicomTag.StudyInstanceUID)} \r\n" +
$"Study Date: {response.Dataset.Get<DateTime>(DicomTag.StudyDate)} \r\n" +
$"Series Count: {response.Dataset.Get<string>(DicomTag.NumberOfStudyRelatedSeries)} \r\n");
}
else if (response.Status == DicomStatus.Success)
{
Log("Study Find Response Status: " + response.Status.ToString() + "\r\n");
}
}
catch (Exception ex)
{
Log("Study Find Response Exception: " + ex.Message + "\r\n");
}
}
public static void FindStudySeries(List<string> studyUids)
{
try
{
DicomClient client = new DicomClient();
client.NegotiateAsyncOps();
foreach (string studyUid in studyUids)
{
Log("_____________________SERIES_____________________ \r\n");
var cSeriesFindRequest = DicomCFindRequest.CreateSeriesQuery(studyInstanceUid: studyUid);
List<string> seriesUids = new List<string>();
bool? findComplete = null;
cSeriesFindRequest.OnResponseReceived += (DicomCFindRequest series_request, DicomCFindResponse series_response) =>
{
DisplaySeriesResponse(series_response);
if (series_response.Status.State == DicomState.Pending)
{
seriesUids.Add(series_response.Dataset?.Get<string>(DicomTag.SeriesInstanceUID));
findComplete = false;
}
else if (series_response.Status.State == DicomState.Success)
{
findComplete = true;
}
else if (series_response.Status.State == DicomState.Failure)
{
findComplete = true;
}
else if (series_response.Status.State == DicomState.Warning)
{
findComplete = false;
}
else if (series_response.Status.State == DicomState.Cancel)
{
findComplete = true;
}
};
client.AddRequest(cSeriesFindRequest);
client.Send(ServerHost, ServerPort, false, LocalAET, ServerAET);
while (findComplete != true)
{
// Log("waiting...waiting....");
}
//MoveSeriesInstances(studyUid, seriesUids);
}
MoveStudyInstances(studyUids);
}
catch (Exception ex)
{
Log("Series Find Exception: " + ex.Message + "\r\n");
}
}
public static void DisplaySeriesResponse(DicomCFindResponse response)
{
try
{
if (response.Status == DicomStatus.Pending)
{
Log($"Assession Number: {response.Dataset.Get<string>(DicomTag.AccessionNumber)} \r\n" +
$"Series Instance ID: {response.Dataset.Get<string>(DicomTag.SeriesInstanceUID)} \r\n" +
$"Series Number: {response.Dataset.Get<string>(DicomTag.SeriesNumber)} \r\n" +
$"Series Modality: {response.Dataset.Get<string>(DicomTag.Modality)} \r\n" +
$"Series Instances: {response.Dataset.Get<int>(DicomTag.NumberOfSeriesRelatedInstances)} \r\n");
}
else if (response.Status == DicomStatus.Success)
{
Log("Series Find Response Status: " + response.Status.ToString() + "\r\n");
}
}
catch (Exception ex)
{
Log("Series Find Response Exception: " + ex.Message + "\r\n");
}
}
public static void MoveStudyInstances(List<string> studyUids)
{
try
{
DicomClient client = new DicomClient();
client.NegotiateAsyncOps();
Log("_____________________MOVE_____________________ \r\n");
foreach (string studyUid in studyUids)
{
var cMoveRequest = new DicomCMoveRequest(LocalAET, studyUid, DicomPriority.High);
Log($"({DateTime.Now}) Sending Request for Study: " + studyUid);
bool? moveComplete = null;
cMoveRequest.OnResponseReceived += (DicomCMoveRequest request, DicomCMoveResponse response) =>
{
DisplayMoveResponse(response);
if (response.Status.State == DicomState.Pending)
{
moveComplete = false;
}
else if (response.Status.State == DicomState.Success)
{
moveComplete = true;
}
else if (response.Status.State == DicomState.Failure)
{
moveComplete = true;
}
else if (response.Status.State == DicomState.Warning)
{
moveComplete = false;
}
else if (response.Status.State == DicomState.Cancel)
{
moveComplete = true;
}
};
client.AddRequest(cMoveRequest);
client.Send(ServerHost, ServerPort, false, LocalAET, ServerAET);
while (moveComplete != true)
{
// Log("waiting...waiting....");
}
Log($"({DateTime.Now}) Move Complete for Study ID: {studyUid} \r\n");
}
Log("All move requests complete");
}
catch (Exception ex)
{
Log("Move Exception: " + ex.Message + "\r\n");
}
}
public static void MoveSeriesInstances(string studyUid, List<string> seriesUids)
{
try
{
DicomClient client = new DicomClient();
client.NegotiateAsyncOps();
Log("_____________________MOVE_____________________ \r\n");
foreach (string seriesUid in seriesUids)
{
var cMoveRequest = new DicomCMoveRequest( LocalAET, studyUid, seriesUid, DicomPriority.High);
Log($"({DateTime.Now}) Sending Request for Series: " + seriesUid);
bool? moveComplete = null;
cMoveRequest.OnResponseReceived += (DicomCMoveRequest request, DicomCMoveResponse response) =>
{
DisplayMoveResponse(response);
if (response.Status.State == DicomState.Pending)
{
moveComplete = false;
}
else if (response.Status.State == DicomState.Success)
{
moveComplete = true;
}
else if (response.Status.State == DicomState.Failure)
{
moveComplete = true;
}
else if (response.Status.State == DicomState.Warning)
{
moveComplete = false;
}
else if (response.Status.State == DicomState.Cancel)
{
moveComplete = true;
}
};
client.AddRequest(cMoveRequest);
client.Send(ServerHost, ServerPort, false, LocalAET, ServerAET);
while (moveComplete != true)
{
// Log("waiting...waiting....");
}
}
Log($"({DateTime.Now}) Move Complete for Study ID: {studyUid} \r\n");
}
catch (Exception ex)
{
Log("Move Exception: " + ex.Message + "\r\n");
}
}
public static void MoveSingleInstance(string studyUid, string seriesUid, string instanceUid)
{
try
{
DicomClient client = new DicomClient();
client.NegotiateAsyncOps();
Log("_____________________MOVE_____________________ \r\n");
var cMoveRequest = new DicomCMoveRequest(LocalAET, studyUid, seriesUid, instanceUid, DicomPriority.High);
Log($"({DateTime.Now}) Sending Request for Instance: {instanceUid}");
bool? moveComplete = null;
cMoveRequest.OnResponseReceived += (DicomCMoveRequest request, DicomCMoveResponse response) =>
{
DisplayMoveResponse(response);
if (response.Status.State == DicomState.Pending)
{
moveComplete = false;
}
else if (response.Status.State == DicomState.Success)
{
moveComplete = true;
}
else if (response.Status.State == DicomState.Failure)
{
moveComplete = true;
}
else if (response.Status.State == DicomState.Warning)
{
moveComplete = false;
}
else if (response.Status.State == DicomState.Cancel)
{
moveComplete = true;
}
};
client.AddRequest(cMoveRequest);
client.Send(ServerHost, ServerPort, false, LocalAET, ServerAET);
while (moveComplete != true)
{
// Log("waiting...waiting....");
}
Log($"({DateTime.Now}) Move Complete for {instanceUid}");
}
catch (Exception ex)
{
Log("Move Exception: " + ex.Message + "\r\n");
}
}
public static void DisplayMoveResponse(DicomCMoveResponse response)
{
try
{
if (response.Status.State == DicomState.Pending)
{
Log($"({DateTime.Now}) Sending is in progress. please wait.. {response.Status.Description}");
}
else if (response.Status.State == DicomState.Success)
{
Log($"({DateTime.Now}) Move Success: " + response.Status.Description + "\r\n");
}
else if (response.Status.State == DicomState.Failure)
{
Log($"({DateTime.Now}) Move Failure: " + response.Status.Description + "\r\n");
}
else if (response.Status.State == DicomState.Warning)
{
Log($"({DateTime.Now}) Move Warning: " + response.Status.Description + "\r\n");
}
else if (response.Status.State == DicomState.Cancel)
{
Log($"({DateTime.Now}) Move Cancel: " + response.Status.Description + "\r\n");
}
}
catch (Exception ex)
{
Log("Move Exception: " + ex.Message + "\r\n");
}
}
}
}
var client = new DicomClient();
var cmove = new DicomCMoveRequest(callingAE, studyInstanceUid);
client.AddRequest(cmove);
client.Send(pacs_IP, pacs_port, false, callingAE, calledAE);
client.Release();
PduListener = ListenAndProcessPDUAsync().ContinueWith(_ => this.Dispose());