public IEnumerable <DicomCGetResponse> OnCGetRequest(DicomCGetRequest request) { IDicomImageFinderService finderService = QRServer.CreateFinderService; List <string> matchingFiles = null; switch (request.Level) { case DicomQueryRetrieveLevel.Patient: matchingFiles = finderService.FindFilesByUID(request.Dataset.Get <string>(DicomTag.PatientID), string.Empty, string.Empty); break; case DicomQueryRetrieveLevel.Study: matchingFiles = finderService.FindFilesByUID(string.Empty, request.Dataset.Get <string>(DicomTag.StudyInstanceUID), string.Empty); break; case DicomQueryRetrieveLevel.Series: matchingFiles = finderService.FindFilesByUID(string.Empty, string.Empty, request.Dataset.Get <string>(DicomTag.SeriesInstanceUID)); break; case DicomQueryRetrieveLevel.Image: yield return(new DicomCGetResponse(request, DicomStatus.QueryRetrieveUnableToPerformSuboperations)); yield break; } foreach (var matchingFile in matchingFiles) { var storeRequest = new DicomCStoreRequest(matchingFile); SendRequest(storeRequest); } yield return(new DicomCGetResponse(request, DicomStatus.Success)); }
public IEnumerable <DicomCMoveResponse> OnCMoveRequest(DicomCMoveRequest request) { // the c-move request contains the DestinationAE. the data of this AE should be configured somewhere. if (request.DestinationAE != "STORESCP") { yield return(new DicomCMoveResponse(request, DicomStatus.QueryRetrieveMoveDestinationUnknown)); yield return(new DicomCMoveResponse(request, DicomStatus.ProcessingFailure)); yield break; } // this data should come from some data storage! var destinationPort = 11112; var destinationIP = "localhost"; IDicomImageFinderService finderService = QRServer.CreateFinderService; List <string> matchingFiles = null; switch (request.Level) { case DicomQueryRetrieveLevel.Patient: matchingFiles = finderService.FindFilesByUID(request.Dataset.Get <string>(DicomTag.PatientID), string.Empty, string.Empty); break; case DicomQueryRetrieveLevel.Study: matchingFiles = finderService.FindFilesByUID(string.Empty, request.Dataset.Get <string>(DicomTag.StudyInstanceUID), string.Empty); break; case DicomQueryRetrieveLevel.Series: matchingFiles = finderService.FindFilesByUID(string.Empty, string.Empty, request.Dataset.Get <string>(DicomTag.SeriesInstanceUID)); break; case DicomQueryRetrieveLevel.Image: yield return(new DicomCMoveResponse(request, DicomStatus.QueryRetrieveUnableToPerformSuboperations)); yield break; } DicomClient client = new DicomClient(); client.NegotiateAsyncOps(); int storeTotal = matchingFiles.Count; int storeDone = 0; // this variable stores the number of instances that have already been sent int storeFailure = 0; // this variable stores the number of faulues returned in a OnResponseReceived foreach (string file in matchingFiles) { var storeRequest = new DicomCStoreRequest(file); // !!! there is a Bug in fo-dicom 3.0.2 that the OnResponseReceived handlers are invoked not until the DicomClient has already // sent all the instances. So the counters are not increased image by image sent but only once in a bulk after all storage // has been finished. This bug will be fixed hopefully soon. storeRequest.OnResponseReceived += (req, resp) => { if (resp.Status == DicomStatus.Success) { Logger.Info("Storage of image successfull"); storeDone++; } else { Logger.Error("Storage of image failed"); storeFailure++; } // SendResponse(new DicomCMoveResponse(request, DicomStatus.Pending) { Remaining = storeTotal - storeDone - storeFailure, Completed = storeDone }); }; client.AddRequest(storeRequest); } // client.Send(destinationIP, destinationPort, false, QRServer.AETitle, request.DestinationAE); var sendTask = client.SendAsync(destinationIP, destinationPort, false, QRServer.AETitle, request.DestinationAE); while (!sendTask.IsCompleted) { // while the send-task is runnin we inform the QR SCU every 2 seconds about the status and how many instances are remaining to send. yield return(new DicomCMoveResponse(request, DicomStatus.Pending) { Remaining = storeTotal - storeDone - storeFailure, Completed = storeDone }); Thread.Sleep(TimeSpan.FromSeconds(2)); } Logger.Info("..fertig"); yield return(new DicomCMoveResponse(request, DicomStatus.Success)); }
/// <summary> /// Testing purposes constructor if you want to inject a custom IDicomImageFinderService /// in unit tests /// </summary> /// <param name="dicomImageFinderService"></param> public WadoUriController(IDicomImageFinderService dicomImageFinderService) { _dicomImageFinderService = dicomImageFinderService; }
public IEnumerable <DicomCFindResponse> OnCFindRequest(DicomCFindRequest request) { var queryLevel = request.Level; var matchingFiles = new List <string>(); IDicomImageFinderService finderService = QRServer.CreateFinderService; // a QR SCP has to define in a DICOM Conformance Statement for which dicom tags it can query // depending on the level of the query. Below there are only very few parameters evaluated. switch (queryLevel) { case DicomQueryRetrieveLevel.Patient: { var patname = request.Dataset.Get(DicomTag.PatientName, string.Empty); var patid = request.Dataset.Get(DicomTag.PatientID, string.Empty); matchingFiles = finderService.FindPatientFiles(patname, patid); } break; case DicomQueryRetrieveLevel.Study: { var patname = request.Dataset.Get(DicomTag.PatientName, string.Empty); var patid = request.Dataset.Get(DicomTag.PatientID, string.Empty); var accNr = request.Dataset.Get(DicomTag.AccessionNumber, string.Empty); var studyUID = request.Dataset.Get(DicomTag.StudyInstanceUID, string.Empty); matchingFiles = finderService.FindStudyFiles(patname, patid, accNr, studyUID); } break; case DicomQueryRetrieveLevel.Series: { var patname = request.Dataset.Get(DicomTag.PatientName, string.Empty); var patid = request.Dataset.Get(DicomTag.PatientID, string.Empty); var accNr = request.Dataset.Get(DicomTag.AccessionNumber, string.Empty); var studyUID = request.Dataset.Get(DicomTag.StudyInstanceUID, string.Empty); var seriesUID = request.Dataset.Get(DicomTag.SeriesInstanceUID, string.Empty); var modality = request.Dataset.Get(DicomTag.Modality, string.Empty); matchingFiles = finderService.FindSeriesFiles(patname, patid, accNr, studyUID, seriesUID, modality); } break; case DicomQueryRetrieveLevel.Image: yield return(new DicomCFindResponse(request, DicomStatus.QueryRetrieveUnableToProcess)); yield break; } // now read the required dicomtags from the matching files and return as results foreach (var matchingFile in matchingFiles) { var dicomFile = DicomFile.Open(matchingFile); var result = new DicomDataset(); foreach (var requestedTag in request.Dataset) { // most of the requested DICOM tags are stored in the DICOM files and therefore saved into a database. // you can fill the responses by selecting the values from the database. // also be aware that there are some requested DicomTags like "ModalitiesInStudy" or "NumberOfStudyRelatedInstances" // or "NumberOfPatientRelatedInstances" and so on which have to be calculated and cannot be read from a DICOM file. if (dicomFile.Dataset.Contains(requestedTag.Tag)) { dicomFile.Dataset.CopyTo(result, requestedTag.Tag); } // else if (requestedTag == DicomTag.NumberOfStudyRelatedInstances) // { // ... somehow calculate how many instances are stored within the study // result.Add(DicomTag.NumberOfStudyRelatedInstances, number); // } .... else { result.Add(requestedTag); } } yield return(new DicomCFindResponse(request, DicomStatus.Pending) { Dataset = result }); } yield return(new DicomCFindResponse(request, DicomStatus.Success)); }
/// <summary> /// Initialize a new instance of WadoUriController /// </summary> public WadoUriController() { //Put your own IDicomImageFinderService implementation here for real world scenarios _dicomImageFinderService = new TestDicomImageFinderService(); }
public IEnumerable <DicomCFindResponse> OnCFindRequest(DicomCFindRequest request) { var queryLevel = request.Level; DataTable resultsDt = null; IDicomImageFinderService finderService = QRServer.CreateFinderService; // a QR SCP has to define in a DICOM Conformance Statement for which dicom tags it can query // depending on the level of the query. Below there are only very few parameters evaluated. switch (queryLevel) { case DicomQueryRetrieveLevel.Patient: { var patname = request.Dataset.GetSingleValueOrDefault(DicomTag.PatientName, string.Empty); var patid = request.Dataset.GetSingleValueOrDefault(DicomTag.PatientID, string.Empty); resultsDt = finderService.FindPatientFiles(patname, patid); } break; case DicomQueryRetrieveLevel.Study: { var patname = request.Dataset.GetSingleValueOrDefault(DicomTag.PatientName, string.Empty); var patid = request.Dataset.GetSingleValueOrDefault(DicomTag.PatientID, string.Empty); var accNr = request.Dataset.GetSingleValueOrDefault(DicomTag.AccessionNumber, string.Empty); var studyUID = request.Dataset.GetSingleValueOrDefault(DicomTag.StudyInstanceUID, string.Empty); var StudyDate = request.Dataset.GetSingleValueOrDefault(DicomTag.StudyDate, string.Empty); var StudyTime = request.Dataset.GetSingleValueOrDefault(DicomTag.StudyTime, string.Empty); resultsDt = finderService.FindStudyFiles(patname, patid, accNr, studyUID, StudyDate, StudyTime); } break; case DicomQueryRetrieveLevel.Series: { var patname = request.Dataset.GetSingleValueOrDefault(DicomTag.PatientName, string.Empty); var patid = request.Dataset.GetSingleValueOrDefault(DicomTag.PatientID, string.Empty); var accNr = request.Dataset.GetSingleValueOrDefault(DicomTag.AccessionNumber, string.Empty); var studyUID = request.Dataset.GetSingleValueOrDefault(DicomTag.StudyInstanceUID, string.Empty); var seriesUID = request.Dataset.GetSingleValueOrDefault(DicomTag.SeriesInstanceUID, string.Empty); var modality = request.Dataset.GetSingleValueOrDefault(DicomTag.Modality, string.Empty); resultsDt = finderService.FindSeriesFiles(patname, patid, accNr, studyUID, seriesUID, modality); } break; case DicomQueryRetrieveLevel.Image: yield return(new DicomCFindResponse(request, DicomStatus.QueryRetrieveUnableToProcess)); yield break; } bool _autoValidateDICOM = Config.GetConfigBoolValueByName(Config.Key_Enable_DICOM_AutoValidate); var columns = new List <string>(); foreach (DataColumn column in resultsDt.Columns) { columns.Add(column.ColumnName); } // now read the required dicomtags from the matching files and return as results foreach (DataRow row in resultsDt.Rows) { var rtnResult = new DicomDataset(); rtnResult.AutoValidate = _autoValidateDICOM; //Not sure if we need this so se up as config value //rtnResult.Clear(); //Could clear existing rather than create new. foreach (var requestedTag in request.Dataset) { // most of the requested DICOM tags are stored in the DICOM files and therefore saved into a database. // you can fill the responses by selecting the values from the database. // also be aware that there are some requested DicomTags like "ModalitiesInStudy" or "NumberOfStudyRelatedInstances" // or "NumberOfPatientRelatedInstances" and so on which have to be calculated and cannot be read from a DICOM file. string columnName = requestedTag.Tag.DictionaryEntry.Keyword.ToString(); if (columns.Contains(columnName)) { rtnResult.Add(requestedTag.Tag, row[columnName].ToString()); } else { rtnResult.Add(requestedTag); } } yield return(new DicomCFindResponse(request, DicomStatus.Pending) { Dataset = rtnResult }); } resultsDt.Dispose(); yield return(new DicomCFindResponse(request, DicomStatus.Success)); }
public IEnumerable <DicomCMoveResponse> OnCMoveRequest(DicomCMoveRequest request) { // The c-move request contains the DestinationAE. The data of this AE should be configured somewhere. if (request.DestinationAE != "") { yield return(new DicomCMoveResponse(request, DicomStatus.QueryRetrieveMoveDestinationUnknown)); yield return(new DicomCMoveResponse(request, DicomStatus.ProcessingFailure)); yield break; } // This data should come from some data storage. var destinationPort = 11112; var destinationIP = "localhost"; IDicomImageFinderService finderService = ServiceLocator.DicomImageFinderService; List <string> matchingFiles = new List <string>(); switch (request.Level) { case DicomQueryRetrieveLevel.Patient: string patientId = request.Dataset.GetSingleValue <string>(DicomTag.PatientID); matchingFiles = finderService.FindFilesByPatient(patientId); break; case DicomQueryRetrieveLevel.Study: string studyUID = request.Dataset.GetSingleValue <string>(DicomTag.StudyInstanceUID); matchingFiles = finderService.FindFilesByStudyUID(studyUID); break; case DicomQueryRetrieveLevel.Series: string seriesUID = request.Dataset.GetSingleValue <string>(DicomTag.SeriesInstanceUID); matchingFiles = finderService.FindFilesBySeriesUID(seriesUID); break; case DicomQueryRetrieveLevel.Image: yield return(new DicomCMoveResponse(request, DicomStatus.QueryRetrieveUnableToPerformSuboperations)); yield break; } // Send to c-store. DicomClient client = new DicomClient(); client.NegotiateAsyncOps(); int storeTotal = matchingFiles.Count; int storeDone = 0; int storeFailure = 0; foreach (var file in matchingFiles) { var storeRequest = new DicomCStoreRequest(file); storeRequest.OnResponseReceived += (req, resp) => { if (resp.Status == DicomStatus.Success) { storeDone++; } else { storeFailure++; } SendResponseAsync(new DicomCMoveResponse(request, DicomStatus.Pending) { Remaining = storeTotal - storeDone - storeFailure, Completed = storeDone }).Wait(); }; client.AddRequest(storeRequest); } var sendTask = client.SendAsync(destinationIP, destinationPort, false, CalledAE, request.DestinationAE); sendTask.Wait(); yield return(new DicomCMoveResponse(request, DicomStatus.Success)); }