public bool SaveStreamData(DicomMessage message, byte[] data, int offset, int count) { var importer = new SopInstanceImporter(_importContext); var sopInstanceUid = message.DataSet[DicomTags.SopInstanceUid].GetString(0, string.Empty); if (_fileStream == null) { if (!importer.GetStreamedFileStorageFolder(message, out _sourceFolder, out _filesystemStreamingFolder)) { Platform.Log(LogLevel.Warn, "Unable to create a folder to save SOP Instance, rejecting: {0}", sopInstanceUid); return false; } _sourceFilename = Path.Combine(_sourceFolder, Guid.NewGuid().ToString() + ServerPlatform.DicomFileExtension); try { _fileStream = FileStreamOpener.OpenForSoleUpdate(_sourceFilename, FileMode.Create); } catch (Exception x) { Platform.Log(LogLevel.Warn, x, "Unable to open file for saving filestream: {0}", _sourceFilename); return false; } } _fileStream.Write(data, offset, count); return true; }
public bool SaveStreamData(DicomMessage message, byte[] data, int offset, int length) { if (_rejectFile) return true; if (_fileStream == null) { _sourceFolder = _context.StorageConfiguration.FileStoreIncomingFolder; _sourceFilename = Path.Combine(_sourceFolder, Guid.NewGuid().ToString() + ".cc"); try { _fileStream = FileStreamOpener.OpenForSoleUpdate(_sourceFilename, FileMode.Create); } catch (Exception x) { Platform.Log(LogLevel.Warn, x, "Unable to open file for saving filestream: {0}", _sourceFilename); return false; } } _fileStream.Write(data, offset, length); return true; }
public void OnReceiveRequestMessage(DicomServer server, ServerAssociationParameters association, byte presentationID, ClearCanvas.Dicom.DicomMessage message) { foreach (byte pcid in association.GetPresentationContextIDs()) { DicomPresContext context = association.GetPresentationContext(pcid); if (context.Result == DicomPresContextResult.Accept) { if (context.AbstractSyntax == SopClass.StudyRootQueryRetrieveInformationModelFind) { DicomMessage response = new DicomMessage(); response.DataSet[DicomTags.StudyInstanceUid].SetStringValue("1.2.3"); response.DataSet[DicomTags.PatientId].SetStringValue("1"); response.DataSet[DicomTags.PatientsName].SetStringValue("test"); response.DataSet[DicomTags.StudyId].SetStringValue("1"); response.DataSet[DicomTags.StudyDescription].SetStringValue("dummy"); server.SendCFindResponse(presentationID, message.MessageId, response, DicomStatuses.Pending); DicomMessage finalResponse = new DicomMessage(); server.SendCFindResponse(presentationID, message.MessageId, finalResponse, DicomStatuses.Success); } else if (context.AbstractSyntax == SopClass.VerificationSopClass) { server.SendCEchoResponse(presentationID, message.MessageId, DicomStatuses.Success); } } } }
public override bool ReceiveMessageAsFileStream(Dicom.Network.DicomServer server, ServerAssociationParameters association, byte presentationId, DicomMessage message) { var sopClassUid = message.AffectedSopClassUid; if (sopClassUid.Equals(SopClass.BreastTomosynthesisImageStorageUid) || sopClassUid.Equals(SopClass.EnhancedCtImageStorageUid) || sopClassUid.Equals(SopClass.EnhancedMrColorImageStorageUid) || sopClassUid.Equals(SopClass.EnhancedMrImageStorageUid) || sopClassUid.Equals(SopClass.EnhancedPetImageStorageUid) || sopClassUid.Equals(SopClass.EnhancedUsVolumeStorageUid) || sopClassUid.Equals(SopClass.EnhancedXaImageStorageUid) || sopClassUid.Equals(SopClass.EnhancedXrfImageStorageUid) || sopClassUid.Equals(SopClass.UltrasoundMultiFrameImageStorageUid) || sopClassUid.Equals(SopClass.MultiFrameGrayscaleByteSecondaryCaptureImageStorageUid) || sopClassUid.Equals(SopClass.MultiFrameGrayscaleWordSecondaryCaptureImageStorageUid) || sopClassUid.Equals(SopClass.MultiFrameSingleBitSecondaryCaptureImageStorageUid) || sopClassUid.Equals(SopClass.MultiFrameTrueColorSecondaryCaptureImageStorageUid)) { server.DimseDatasetStopTag = DicomTagDictionary.GetDicomTag(DicomTags.ReconstructionIndex); // Random tag at the end of group 20 server.StreamMessage = true; return true; } return false; }
/// <summary> /// Converts a <see cref="DicomMessage"/> instance into a <see cref="DicomFile"/>. /// </summary> /// <remarks>This routine sets the Source AE title, </remarks> /// <param name="message"></param> /// <param name="filename"></param> /// <param name="assocParms"></param> /// <returns></returns> protected static DicomFile ConvertToDicomFile(DicomMessage message, string filename, AssociationParameters assocParms) { // This routine sets some of the group 0x0002 elements. DicomFile file = new DicomFile(message, filename); file.SourceApplicationEntityTitle = assocParms.CallingAE; file.TransferSyntax = message.TransferSyntax; return file; }
/// <summary> /// Populate at the IMAGE level a response message. /// </summary> /// <param name="request"></param> /// <param name="response"></param> /// <param name="tagList"></param> /// <param name="theInstanceStream"></param> private void PopulateInstance(DicomAttributeCollection request, DicomMessage response, List<uint> tagList, InstanceXml theInstanceStream) { DicomAttributeCollection dataSet = response.DataSet; dataSet[DicomTags.RetrieveAeTitle].SetStringValue(Partition.AeTitle); dataSet[DicomTags.InstanceAvailability].SetStringValue("ONLINE"); DicomAttributeCollection sourceDataSet = theInstanceStream.Collection; if (false == sourceDataSet.Contains(DicomTags.SpecificCharacterSet)) { dataSet[DicomTags.SpecificCharacterSet].SetStringValue(sourceDataSet[DicomTags.SpecificCharacterSet].ToString()); dataSet.SpecificCharacterSet = sourceDataSet[DicomTags.SpecificCharacterSet].ToString(); // this will ensure the data is encoded using the specified character set } foreach (uint tag in tagList) { try { switch (tag) { case DicomTags.PatientId: dataSet[DicomTags.PatientId].SetStringValue(request[DicomTags.PatientId].ToString()); break; case DicomTags.StudyInstanceUid: dataSet[DicomTags.StudyInstanceUid].SetStringValue( request[DicomTags.StudyInstanceUid].ToString()); break; case DicomTags.SeriesInstanceUid: dataSet[DicomTags.SeriesInstanceUid].SetStringValue( request[DicomTags.SeriesInstanceUid].ToString()); break; case DicomTags.QueryRetrieveLevel: dataSet[DicomTags.QueryRetrieveLevel].SetStringValue("IMAGE"); break; default: if (sourceDataSet.Contains(tag)) dataSet[tag] = sourceDataSet[tag].Copy(); else dataSet[tag].SetNullValue(); break; // Meta tags that should have not been in the RQ, but we've already set case DicomTags.RetrieveAeTitle: case DicomTags.InstanceAvailability: case DicomTags.SpecificCharacterSet: break; } } catch (Exception e) { Platform.Log(LogLevel.Warn, e, "Unexpected error setting tag {0} in C-FIND-RSP", dataSet[tag].Tag.ToString()); dataSet[tag].SetNullValue(); } } }
public override IDicomFilestreamHandler OnStartFilestream(Dicom.Network.DicomServer server, ServerAssociationParameters association, byte presentationId, DicomMessage message) { if (_importContext == null) { LoadImportContext(association); } return new StorageFilestreamHandler(Context, _importContext); }
private void SendCFind() { DicomMessage msg = new DicomMessage(); DicomAttributeCollection cFindDataset = msg.DataSet; // set the Query Retrieve Level cFindDataset[DicomTags.QueryRetrieveLevel].SetStringValue("STUDY"); // set the other tags we want to retrieve cFindDataset[DicomTags.StudyInstanceUid].SetStringValue(""); cFindDataset[DicomTags.PatientsName].SetStringValue(""); cFindDataset[DicomTags.PatientId].SetStringValue(""); cFindDataset[DicomTags.ModalitiesInStudy].SetStringValue(""); cFindDataset[DicomTags.StudyDescription].SetStringValue(""); byte pcid = _dicomClient.AssociationParams.FindAbstractSyntax(SopClass.StudyRootQueryRetrieveInformationModelFind); _dicomClient.SendCFindRequest(pcid, _dicomClient.NextMessageID(), msg); }
public void OnReceiveResponseMessage(DicomClient client, ClientAssociationParameters association, byte presentationID, DicomMessage message) { if (message.Status.Status == DicomState.Pending) { string studyinstanceuid = message.DataSet[DicomTags.StudyInstanceUid].GetString(0, ""); if (OnResultReceive != null) OnResultReceive(message.DataSet); } else { _dicomClient.SendReleaseRequest(); } }
public void OnReceiveRequestMessage(DicomClient client, ClientAssociationParameters association, byte presentationID, DicomMessage message) { }
private void OnReceiveCancelRequest(DicomMessage message) { lock (_syncLock) { foreach (SendOperationInfo info in _sendOperations) { if (info.MessageId == message.MessageIdBeingRespondedTo) { RemoveSendOperationInfo(info); WorkItemService.WorkItemService.Instance.Update(new WorkItemUpdateRequest { Cancel = true, Identifier = info.WorkItemData.Identifier }); } } } }
public void OnReceiveRequestMessage(DicomServer server, ServerAssociationParameters association, byte presentationID, ClearCanvas.Dicom.DicomMessage message) { foreach (byte pcid in association.GetPresentationContextIDs()) { DicomPresContext context = association.GetPresentationContext(pcid); if (context.Result == DicomPresContextResult.Accept) { if (context.AbstractSyntax == SopClass.StudyRootQueryRetrieveInformationModelFind) { DicomMessage response = new DicomMessage(); response.DataSet[DicomTags.StudyInstanceUid].SetStringValue("1.2.3"); response.DataSet[DicomTags.PatientId].SetStringValue("1"); response.DataSet[DicomTags.PatientsName].SetStringValue("test"); response.DataSet[DicomTags.StudyId].SetStringValue("1"); response.DataSet[DicomTags.StudyDescription].SetStringValue("dummy"); server.SendCFindResponse(presentationID, message.MessageId, response, DicomStatuses.Pending); DicomMessage finalResponse = new DicomMessage(); server.SendCFindResponse(presentationID, message.MessageId, finalResponse, DicomStatuses.Success); } else if (context.AbstractSyntax == SopClass.VerificationSopClass) { server.SendCEchoResponse(presentationID, message.MessageId, DicomStatuses.Success); } } } }
public override bool OnReceiveRequest(Dicom.Network.DicomServer server, ServerAssociationParameters association, byte presentationID, DicomMessage message) { string studyInstanceUid; string seriesInstanceUid; DicomUid sopInstanceUid; bool ok = message.DataSet[DicomTags.SopInstanceUid].TryGetUid(0, out sopInstanceUid); if (ok) ok = message.DataSet[DicomTags.SeriesInstanceUid].TryGetString(0, out seriesInstanceUid); if (ok) ok = message.DataSet[DicomTags.StudyInstanceUid].TryGetString(0, out studyInstanceUid); if (!ok) { Platform.Log(LogLevel.Error, "Unable to retrieve UIDs from request message, sending failure status."); server.SendCStoreResponse(presentationID, message.MessageId, sopInstanceUid.UID, DicomStatuses.ProcessingFailure); return true; } if (_importContext == null) { LoadImportContext(association); } var importer = new ImportFilesUtility(_importContext); var result = importer.Import(message, BadFileBehaviourEnum.Ignore, FileImportBehaviourEnum.Save); if (result.Successful) { if (!String.IsNullOrEmpty(result.AccessionNumber)) Platform.Log(LogLevel.Info, "Received SOP Instance {0} from {1} to {2} (A#:{3} StudyUid:{4})", result.SopInstanceUid, association.CallingAE, association.CalledAE, result.AccessionNumber, result.StudyInstanceUid); else Platform.Log(LogLevel.Info, "Received SOP Instance {0} from {1} to {2} (StudyUid:{3})", result.SopInstanceUid, association.CallingAE, association.CalledAE, result.StudyInstanceUid); server.SendCStoreResponse(presentationID, message.MessageId, message.AffectedSopInstanceUid, result.DicomStatus); } else { if (result.DicomStatus == DicomStatuses.ProcessingFailure) Platform.Log(LogLevel.Error, "Failure importing sop: {0}", result.ErrorMessage); //OnReceiveError(message, result.ErrorMessage, association.CallingAE); server.SendCStoreResponse(presentationID, message.MessageId, message.AffectedSopInstanceUid, result.DicomStatus, result.ErrorMessage); } return true; }
/// <summary> /// Method for processing Image level queries. /// </summary> /// <param name="server"></param> /// <param name="presentationId"></param> /// <param name="message"></param> /// <returns></returns> private void OnReceiveImageLevelQuery(DicomServer server, byte presentationId, DicomMessage message) { var tagList = new List<DicomTag>(); var matchingTagList = new List<uint>(); DicomAttributeCollection data = message.DataSet; string studyInstanceUid = data[DicomTags.StudyInstanceUid].GetString(0, String.Empty); string seriesInstanceUid = data[DicomTags.SeriesInstanceUid].GetString(0, String.Empty); StudyStorageLocation location; try { FilesystemMonitor.Instance.GetReadableStudyStorageLocation(Partition.Key, studyInstanceUid, StudyRestore.True, StudyCache.True, out location); } catch (Exception e) { Platform.Log(LogLevel.Error, "Unable to load storage location for study {0}: {1}", studyInstanceUid, e.Message); var failureResponse = new DicomMessage(); failureResponse.DataSet[DicomTags.InstanceAvailability].SetStringValue("NEARLINE"); failureResponse.DataSet[DicomTags.QueryRetrieveLevel].SetStringValue("IMAGE"); failureResponse.DataSet[DicomTags.RetrieveAeTitle].SetStringValue(Partition.AeTitle); failureResponse.DataSet[DicomTags.StudyInstanceUid].SetStringValue(studyInstanceUid); failureResponse.DataSet[DicomTags.SeriesInstanceUid].SetStringValue(seriesInstanceUid); server.SendCFindResponse(presentationId, message.MessageId, failureResponse, DicomStatuses.QueryRetrieveUnableToProcess); AuditLog(server.AssociationParams, EventIdentificationContentsEventOutcomeIndicator.SeriousFailureActionTerminated, message); return; } try { // Will always return a value, although it may be an empty StudyXml file StudyXml studyXml = LoadStudyXml(location); SeriesXml seriesXml = studyXml[seriesInstanceUid]; if (seriesXml == null) { var failureResponse = new DicomMessage(); failureResponse.DataSet[DicomTags.QueryRetrieveLevel].SetStringValue("IMAGE"); server.SendCFindResponse(presentationId, message.MessageId, failureResponse, DicomStatuses.QueryRetrieveUnableToProcess); AuditLog(server.AssociationParams, EventIdentificationContentsEventOutcomeIndicator.SeriousFailureActionTerminated, message); return; } foreach (DicomAttribute attrib in message.DataSet) { if (attrib.Tag.TagValue.Equals(DicomTags.SpecificCharacterSet) || attrib.Tag.TagValue.Equals(DicomTags.QueryRetrieveLevel)) continue; tagList.Add(attrib.Tag); if (!attrib.IsNull) matchingTagList.Add(attrib.Tag.TagValue); } int resultCount = 0; foreach (InstanceXml theInstanceStream in seriesXml) { if (CompareInstanceMatch(message, matchingTagList, theInstanceStream)) { if (CancelReceived) { var failureResponse = new DicomMessage(); failureResponse.DataSet[DicomTags.QueryRetrieveLevel].SetStringValue("IMAGE"); server.SendCFindResponse(presentationId, message.MessageId, failureResponse, DicomStatuses.Cancel); AuditLog(server.AssociationParams, EventIdentificationContentsEventOutcomeIndicator.Success, message); return; } resultCount++; if (DicomSettings.Default.MaxQueryResponses != -1 && DicomSettings.Default.MaxQueryResponses < resultCount) { SendBufferedResponses(server, presentationId, message); Platform.Log(LogLevel.Warn, "Maximum Configured Query Responses Exceeded: " + resultCount); break; } var response = new DicomMessage(); PopulateInstance(message, response, tagList, theInstanceStream); _responseQueue.Enqueue(response); if (_responseQueue.Count >= DicomSettings.Default.BufferedQueryResponses) SendBufferedResponses(server, presentationId, message); } } SendBufferedResponses(server, presentationId, message); var finalResponse = new DicomMessage(); server.SendCFindResponse(presentationId, message.MessageId, finalResponse, DicomStatuses.Success); AuditLog(server.AssociationParams, EventIdentificationContentsEventOutcomeIndicator.Success, message); } catch (Exception e) { Platform.Log(LogLevel.Error, e, "Unexepected exception processing IMAGE level query for study {0}: {1}", studyInstanceUid, e.Message); var failureResponse = new DicomMessage(); failureResponse.DataSet[DicomTags.InstanceAvailability].SetStringValue("ONLINE"); failureResponse.DataSet[DicomTags.QueryRetrieveLevel].SetStringValue("IMAGE"); failureResponse.DataSet[DicomTags.RetrieveAeTitle].SetStringValue(Partition.AeTitle); failureResponse.DataSet[DicomTags.StudyInstanceUid].SetStringValue(studyInstanceUid); failureResponse.DataSet[DicomTags.SeriesInstanceUid].SetStringValue(seriesInstanceUid); server.SendCFindResponse(presentationId, message.MessageId, failureResponse, DicomStatuses.QueryRetrieveUnableToProcess); AuditLog(server.AssociationParams, EventIdentificationContentsEventOutcomeIndicator.SeriousFailureActionTerminated, message); } return; }
/// <summary> /// Helper method for logging audit information. /// </summary> /// <param name="parms"></param> /// <param name="outcome"></param> /// <param name="msg">The query message to be audited</param> private static void AuditLog(AssociationParameters parms, EventIdentificationContentsEventOutcomeIndicator outcome, DicomMessage msg) { try { var helper = new QueryAuditHelper(ServerPlatform.AuditSource, outcome, parms, msg.AffectedSopClassUid, msg.DataSet); ServerPlatform.LogAuditMessage(helper); } catch (Exception e) { Platform.Log(LogLevel.Warn, "Unexpected exception logging DICOM Query audit message: {0}", e.Message); } }
public void OnReceiveResponseMessage(DicomClient client, ClientAssociationParameters association, byte presentationID, DicomMessage message) { if (message.Status.Status != DicomState.Success) { Logger.LogError("Failure status received in sending C-STORE: {0}", message.Status.Description); } bool ok = false; while (ok == false) { _fileListIndex++; if (_fileListIndex >= _fileList.Count) { Logger.LogInfo("Completed sending C-STORE-RQ messages, releasing association."); client.SendReleaseRequest(); return; } ok = SendCStore(client, association); } }
public void OnReceiveRequestMessage(DicomClient client, ClientAssociationParameters association, byte presentationID, DicomMessage message) { Logger.LogError("Unexpected OnReceiveRequestMessage callback on client."); throw new Exception("The method or operation is not implemented."); }
/// <summary> /// Generic routine to send the next C-STORE-RQ message in the _fileList. /// </summary> /// <param name="client">DICOM Client class</param> /// <param name="association">Association Parameters</param> public bool SendCStore(DicomClient client, ClientAssociationParameters association) { FileToSend fileToSend = _fileList[_fileListIndex]; DicomFile dicomFile = new DicomFile(fileToSend.filename); try { dicomFile.Load(DicomReadOptions.Default); } catch (DicomException e) { Logger.LogErrorException(e, "Unexpected exception when loading DICOM file {0}",fileToSend.filename); return false; } DicomMessage msg = new DicomMessage(dicomFile); byte pcid = association.FindAbstractSyntaxWithTransferSyntax(fileToSend.sopClass, dicomFile.TransferSyntax); if (pcid == 0) { if (dicomFile.TransferSyntax.Equals(TransferSyntax.ImplicitVrLittleEndian)) pcid = association.FindAbstractSyntaxWithTransferSyntax(fileToSend.sopClass, TransferSyntax.ExplicitVrLittleEndian); if (pcid == 0) { Logger.LogError( "Unable to find matching negotiated presentation context for sop {0} and syntax {1}", dicomFile.SopClass.Name, dicomFile.TransferSyntax.Name); return false; } } client.SendCStoreRequest(pcid, client.NextMessageID(), DicomPriority.Medium, msg); return true; }
public bool CompleteStream(DicomServer server, ServerAssociationParameters assoc, byte presentationId, DicomMessage message) { DicomProcessingResult result; try { if (_fileStream != null) { _fileStream.Flush(true); _fileStream.Close(); _fileStream.Dispose(); _fileStream = null; } var importer = new SopInstanceImporter(_importContext); result = importer.ImportFile(message, _sourceFilename); if (result.Successful) { if (!String.IsNullOrEmpty(result.AccessionNumber)) Platform.Log(LogLevel.Info, "Received SOP Instance {0} from {1} to {2} (A#:{3} StudyUid:{4})", result.SopInstanceUid, assoc.CallingAE, assoc.CalledAE, result.AccessionNumber, result.StudyInstanceUid); else Platform.Log(LogLevel.Info, "Received SOP Instance {0} from {1} to {2} (StudyUid:{3})", result.SopInstanceUid, assoc.CallingAE, assoc.CalledAE, result.StudyInstanceUid); } } catch (Exception e) { result = new DicomProcessingResult { DicomStatus = DicomStatuses.ProcessingFailure, ErrorMessage = e.Message }; } if (!result.Successful) { Platform.Log(LogLevel.Warn, "Failure importing sop: {0}", result.ErrorMessage); } CleanupDirectory(); server.SendCStoreResponse(presentationId, message.MessageId, message.AffectedSopInstanceUid, result.DicomStatus); return true; }
private void UpdateProgress(WorkItemData workItem) { try { SendOperationInfo sendOperationInfo = GetSendOperationInfo(workItem); if (sendOperationInfo == null) { return; } sendOperationInfo.WorkItemData = workItem; var progress = GetProgressByMessageId(sendOperationInfo.MessageId); var msg = new DicomMessage(); DicomStatus status; if (workItem.Status == WorkItemStatusEnum.Failed) { sendOperationInfo.Complete = true; } else if (progress.RemainingSubOperations == 0 && workItem.Status != WorkItemStatusEnum.Pending) { sendOperationInfo.Complete = true; } if (SendOperationsComplete(sendOperationInfo.MessageId)) { status = DicomStatuses.Success; foreach (SendOperationInfo info in GetSendOperationInfo(sendOperationInfo.MessageId)) { foreach (string sopInstanceUid in info.FailedSopInstanceUids) msg.DataSet[DicomTags.FailedSopInstanceUidList].AppendString(sopInstanceUid); if (workItem.Status == WorkItemStatusEnum.Canceled) status = DicomStatuses.Cancel; else if (workItem.Status == WorkItemStatusEnum.Failed) status = DicomStatuses.QueryRetrieveUnableToProcess; else if (progress.FailureSubOperations > 0 && status == DicomStatuses.Success) status = DicomStatuses.QueryRetrieveSubOpsOneOrMoreFailures; } } else { status = DicomStatuses.Pending; if ((progress.RemainingSubOperations%5) != 0) return; // Only send a RSP every 5 to reduce network load } if (sendOperationInfo.Server.NetworkActive) { sendOperationInfo.Server.SendCMoveResponse(sendOperationInfo.PresentationId, sendOperationInfo.MessageId, msg, status, (ushort) progress.SuccessSubOperations, (ushort) progress.RemainingSubOperations, (ushort) progress.FailureSubOperations, (ushort) progress.WarningSubOperations); } if (status != DicomStatuses.Pending || !sendOperationInfo.Server.NetworkActive) { foreach (SendOperationInfo info in GetSendOperationInfo(sendOperationInfo.MessageId)) { RemoveSendOperationInfo(info); } } } catch (Exception e) { Platform.Log(LogLevel.Error, e, "Unexpected error processing C-MOVE Responses"); } }
public bool CompleteStream(Dicom.Network.DicomServer server, ServerAssociationParameters assoc, byte presentationId, DicomMessage message) { DicomProcessingResult result; var importer = new ImportFilesUtility(_importContext); if (_rejectFile) { result = new DicomProcessingResult(); result.SetError(DicomStatuses.StorageStorageOutOfResources, string.Format("Import failed, disk space usage exceeded")); string studyInstanceUid = message.DataSet[DicomTags.StudyInstanceUid].GetString(0, string.Empty); WorkItem workItem; lock (_importContext.StudyWorkItemsSyncLock) _importContext.StudyWorkItems.TryGetValue(studyInstanceUid, out workItem); importer.InsertFailedWorkItemUid(workItem, message, result); _importContext.FatalError = true; importer.AuditFailure(result); Platform.Log(LogLevel.Warn, "Failure receiving sop, out of disk space: {0}", message.AffectedSopInstanceUid); server.SendCStoreResponse(presentationId, message.MessageId, message.AffectedSopInstanceUid, result.DicomStatus); return true; } try { if (_fileStream != null) { _fileStream.Flush(true); _fileStream.Close(); _fileStream.Dispose(); _fileStream = null; } // Convert to file to pass in the source filename var theFile = new DicomFile(message,_sourceFilename); result = importer.Import(theFile, BadFileBehaviourEnum.Delete, FileImportBehaviourEnum.Move); if (result.Successful) { if (!String.IsNullOrEmpty(result.AccessionNumber)) Platform.Log(LogLevel.Info, "Received SOP Instance {0} from {1} to {2} (A#:{3} StudyUid:{4})", result.SopInstanceUid, assoc.CallingAE, assoc.CalledAE, result.AccessionNumber, result.StudyInstanceUid); else Platform.Log(LogLevel.Info, "Received SOP Instance {0} from {1} to {2} (StudyUid:{3})", result.SopInstanceUid, assoc.CallingAE, assoc.CalledAE, result.StudyInstanceUid); } } catch (Exception e) { result = new DicomProcessingResult { DicomStatus = DicomStatuses.ProcessingFailure, ErrorMessage = e.Message }; } if (!result.Successful) { Platform.Log(LogLevel.Warn, "Failure importing sop: {0}", result.ErrorMessage); } CleanupFile(); server.SendCStoreResponse(presentationId, message.MessageId, message.AffectedSopInstanceUid, result.DicomStatus); return true; }
private void OnReceiveMoveSeriesRequest(ClearCanvas.Dicom.Network.DicomServer server, byte presentationID, DicomMessage message, IDicomServiceNode remoteAEInfo) { string studyInstanceUid = message.DataSet[DicomTags.StudyInstanceUid].GetString(0, ""); var seriesUids = (string[])message.DataSet[DicomTags.SeriesInstanceUid].Values; lock (_syncLock) { int subOperations = 0; using (var context = new DataAccessContext()) { var results = context.GetStudyStoreQuery().SeriesQuery(new SeriesIdentifier { StudyInstanceUid = studyInstanceUid, }); foreach (SeriesIdentifier series in results) { foreach (string seriesUid in seriesUids) if (series.SeriesInstanceUid.Equals(seriesUid) && series.NumberOfSeriesRelatedInstances.HasValue) { subOperations += series.NumberOfSeriesRelatedInstances.Value; break; } } var s = context.GetStudyStoreQuery().StudyQuery(new StudyRootStudyIdentifier {StudyInstanceUid = studyInstanceUid}); var identifier = CollectionUtils.FirstElement(s); var client = new DicomSendBridge(); client.SendSeries(remoteAEInfo, identifier, seriesUids, WorkItemPriorityEnum.High); _sendOperations.Add(new SendOperationInfo(client.WorkItem, message.MessageId, presentationID, server) { SubOperations = subOperations }); } } }
/// <summary> /// Extension method called when a new DICOM Request message has been called that the /// extension will process. /// </summary> /// <param name="server"></param> /// <param name="association"></param> /// <param name="presentationId"></param> /// <param name="message"></param> /// <returns></returns> public override bool OnReceiveRequest(DicomServer server, ServerAssociationParameters association, byte presentationId, DicomMessage message) { String level = message.DataSet[DicomTags.QueryRetrieveLevel].GetString(0, string.Empty); if (message.CommandField == DicomCommandField.CCancelRequest) { Platform.Log(LogLevel.Info,"Received C-FIND-CANCEL-RQ message."); CancelReceived = true; return true; } CancelReceived = false; if (message.AffectedSopClassUid.Equals(SopClass.StudyRootQueryRetrieveInformationModelFindUid)) { if (level.Equals("STUDY")) { // We use the ThreadPool to process the thread requests. This is so that we return back // to the main message loop, and continue to look for cancel request messages coming // in. There's a small chance this may cause delays in responding to query requests if // the .NET Thread pool fills up. ThreadPool.QueueUserWorkItem(delegate { try { OnReceiveStudyLevelQuery(server, presentationId, message); } catch (Exception x) { Platform.Log(LogLevel.Error, x, "Unexpected exception in OnReceiveStudyLevelQuery."); } }); return true; } if (level.Equals("SERIES")) { ThreadPool.QueueUserWorkItem(delegate { try { OnReceiveSeriesLevelQuery(server, presentationId, message); } catch (Exception x) { Platform.Log(LogLevel.Error, x, "Unexpected exception in OnReceiveSeriesLevelQuery."); } }); return true; } if (level.Equals("IMAGE")) { ThreadPool.QueueUserWorkItem(delegate { try { OnReceiveImageLevelQuery(server, presentationId, message); } catch (Exception x) { Platform.Log(LogLevel.Error, x, "Unexpected exception in OnReceiveImageLevelQuery."); } }); return true; } Platform.Log(LogLevel.Error, "Unexpected Study Root Query/Retrieve level: {0}", level); server.SendCFindResponse(presentationId, message.MessageId, new DicomMessage(), DicomStatuses.QueryRetrieveIdentifierDoesNotMatchSOPClass); return true; } if (message.AffectedSopClassUid.Equals(SopClass.PatientRootQueryRetrieveInformationModelFindUid)) { if (level.Equals("PATIENT")) { ThreadPool.QueueUserWorkItem(delegate { try { OnReceivePatientQuery(server, presentationId, message); } catch (Exception x) { Platform.Log(LogLevel.Error, x, "Unexpected exception in OnReceivePatientQuery."); } }); return true; } if (level.Equals("STUDY")) { ThreadPool.QueueUserWorkItem(delegate { try { OnReceiveStudyLevelQuery(server, presentationId, message); } catch (Exception x) { Platform.Log(LogLevel.Error, x, "Unexpected exception in OnReceiveStudyLevelQuery."); } }); return true; } if (level.Equals("SERIES")) { ThreadPool.QueueUserWorkItem(delegate { try { OnReceiveSeriesLevelQuery(server, presentationId, message); } catch (Exception x) { Platform.Log(LogLevel.Error, x, "Unexpected exception in OnReceiveSeriesLevelQuery."); } }); return true; } if (level.Equals("IMAGE")) { ThreadPool.QueueUserWorkItem(delegate { try { OnReceiveImageLevelQuery(server, presentationId, message); } catch (Exception x) { Platform.Log(LogLevel.Error, x, "Unexpected exception in OnReceiveImageLevelQuery."); } }); return true; } Platform.Log(LogLevel.Error, "Unexpected Patient Root Query/Retrieve level: {0}", level); server.SendCFindResponse(presentationId, message.MessageId, new DicomMessage(), DicomStatuses.QueryRetrieveIdentifierDoesNotMatchSOPClass); return true; } // Not supported message type, send a failure status. server.SendCFindResponse(presentationId, message.MessageId, new DicomMessage(), DicomStatuses.QueryRetrieveIdentifierDoesNotMatchSOPClass); return true; }
public void OnReceiveResponseMessage(DicomServer server, ServerAssociationParameters association, byte presentationID, ClearCanvas.Dicom.DicomMessage message) { server.SendAssociateAbort(DicomAbortSource.ServiceUser, DicomAbortReason.UnexpectedPDU); }
/// <summary> /// Creates a new DicomFile instance from an existing <see cref="DicomMessage"/> instance. /// </summary> /// <remarks> /// <para> /// This routine assigns the existing <see cref="DicomMessage.DataSet"/> into the new /// DicomFile instance. /// </para> /// <para> /// A new <see cref="DicomAttributeCollection"/> is created for the MetaInfo. The /// Media Storage SOP Instance UID, Media Storage SOP Class UID, Implementation Version Name, /// and Implementation Class UID tags are automatically set in the meta information. /// </para> /// </remarks> /// <param name="msg"></param> /// <param name="filename"></param> public DicomFile(DicomMessage msg, String filename) { MetaInfo = new DicomAttributeCollection(0x00020000, 0x0002FFFF); DataSet = msg.DataSet; MediaStorageSopInstanceUid = msg.AffectedSopInstanceUid; MediaStorageSopClassUid = msg.AffectedSopClassUid; ImplementationVersionName = DicomImplementation.Version; ImplementationClassUid = DicomImplementation.ClassUID.UID; if (msg.TransferSyntax.Encapsulated) MetaInfo[DicomTags.TransferSyntaxUid].SetStringValue(msg.TransferSyntax.UidString); else MetaInfo[DicomTags.TransferSyntaxUid].SetStringValue(TransferSyntax.ExplicitVrLittleEndian.UidString); MetaInfo[DicomTags.FileMetaInformationVersion].Values = new byte[] { 0x00, 0x01 }; _filename = filename; }
private void SendBufferedResponses(DicomServer server, byte presentationId, DicomMessage requestMessage) { while (_responseQueue.Count > 0) { DicomMessage response = _responseQueue.Dequeue(); server.SendCFindResponse(presentationId, requestMessage.MessageId, response, DicomStatuses.Pending); if (CancelReceived) throw new DicomException("DICOM C-Cancel Received"); if (!server.NetworkActive) throw new DicomException("Association is no longer valid."); } }
private void OnReceiveMoveStudiesRequest(ClearCanvas.Dicom.Network.DicomServer server, byte presentationID, DicomMessage message, IDicomServiceNode remoteAEInfo) { IEnumerable<string> studyUids = (string[])message.DataSet[DicomTags.StudyInstanceUid].Values; foreach (string studyUid in studyUids) { lock (_syncLock) { int subOperations = 0; using (var context = new DataAccessContext()) { var s = context.GetStudyStoreQuery().StudyQuery(new StudyRootStudyIdentifier {StudyInstanceUid = studyUid}); var identifier = CollectionUtils.FirstElement(s); if (identifier.NumberOfStudyRelatedInstances.HasValue) subOperations = identifier.NumberOfStudyRelatedInstances.Value; var client = new DicomSendBridge(); client.SendStudy(remoteAEInfo, identifier, WorkItemPriorityEnum.High); _sendOperations.Add(new SendOperationInfo(client.WorkItem, message.MessageId, presentationID, server) { SubOperations = subOperations }); } } } }
/// <summary> /// Method for processing Patient level queries. /// </summary> /// <param name="server"></param> /// <param name="presentationId"></param> /// <param name="message">The Patient level query message.</param> /// <returns></returns> private void OnReceivePatientQuery(DicomServer server, byte presentationId, DicomMessage message) { var tagList = new List<DicomTag>(); using (IReadContext read = PersistentStoreRegistry.GetDefaultStore().OpenReadContext()) { var find = read.GetBroker<IPatientEntityBroker>(); var criteria = new PatientSelectCriteria(); criteria.ServerPartitionKey.EqualTo(Partition.GetKey()); DicomAttributeCollection data = message.DataSet; var studySelect = new StudySelectCriteria(); bool studySubSelect = false; foreach (DicomAttribute attrib in message.DataSet) { tagList.Add(attrib.Tag); if (!attrib.IsNull) switch (attrib.Tag.TagValue) { case DicomTags.PatientsName: QueryHelper.SetStringCondition(criteria.PatientsName, data[DicomTags.PatientsName].GetString(0, string.Empty)); break; case DicomTags.PatientId: QueryHelper.SetStringCondition(criteria.PatientId, data[DicomTags.PatientId].GetString(0, string.Empty)); break; case DicomTags.IssuerOfPatientId: QueryHelper.SetStringCondition(criteria.IssuerOfPatientId, data[DicomTags.IssuerOfPatientId].GetString(0, string.Empty)); break; case DicomTags.PatientsSex: // Specify a subselect on Patients Sex in Study QueryHelper.SetStringArrayCondition(studySelect.PatientsSex, (string[])data[DicomTags.PatientsSex].Values); if (!studySubSelect) { criteria.StudyRelatedEntityCondition.Exists(studySelect); studySubSelect = true; } break; case DicomTags.PatientsBirthDate: // Specify a subselect on Patients Birth Date in Study QueryHelper.SetStringArrayCondition(studySelect.PatientsBirthDate, (string[])data[DicomTags.PatientsBirthDate].Values); if (!studySubSelect) { criteria.StudyRelatedEntityCondition.Exists(studySelect); studySubSelect = true; } break; default: foreach (var q in _queryExtensions) { bool extensionSubSelect; q.OnReceivePatientLevelQuery(message, attrib.Tag, criteria, studySelect, out extensionSubSelect); if (extensionSubSelect && !studySubSelect) { criteria.StudyRelatedEntityCondition.Exists(studySelect); studySubSelect = true; } } break; } } int resultCount = 0; try { find.Find(criteria, delegate(Patient row) { if (CancelReceived) throw new DicomException("DICOM C-Cancel Received"); resultCount++; if (DicomSettings.Default.MaxQueryResponses != -1 && DicomSettings.Default.MaxQueryResponses < resultCount) { SendBufferedResponses(server, presentationId, message); throw new DicomException("Maximum Configured Query Responses Exceeded: " + resultCount); } var response = new DicomMessage(); PopulatePatient(response, tagList, row); _responseQueue.Enqueue(response); if (_responseQueue.Count >= DicomSettings.Default.BufferedQueryResponses) SendBufferedResponses(server, presentationId, message); }); SendBufferedResponses(server, presentationId, message); } catch (Exception e) { if (CancelReceived) { var errorResponse = new DicomMessage(); server.SendCFindResponse(presentationId, message.MessageId, errorResponse, DicomStatuses.Cancel); } else if (DicomSettings.Default.MaxQueryResponses != -1 && DicomSettings.Default.MaxQueryResponses < resultCount) { Platform.Log(LogLevel.Warn, "Maximum Configured Query Responses Exceeded: {0} on query from {1}", resultCount, server.AssociationParams.CallingAE); var errorResponse = new DicomMessage(); server.SendCFindResponse(presentationId, message.MessageId, errorResponse, DicomStatuses.Success); AuditLog(server.AssociationParams, EventIdentificationContentsEventOutcomeIndicator.Success, message); } else { Platform.Log(LogLevel.Error, e, "Unexpected exception when processing FIND request."); var errorResponse = new DicomMessage(); server.SendCFindResponse(presentationId, message.MessageId, errorResponse, DicomStatuses.QueryRetrieveUnableToProcess); AuditLog(server.AssociationParams, EventIdentificationContentsEventOutcomeIndicator.SeriousFailureActionTerminated, message); } return; } } var finalResponse = new DicomMessage(); server.SendCFindResponse(presentationId, message.MessageId, finalResponse, DicomStatuses.Success); AuditLog(server.AssociationParams, EventIdentificationContentsEventOutcomeIndicator.Success, message); return; }
private void OnReceiveMoveImageRequest(ClearCanvas.Dicom.Network.DicomServer server, byte presentationID, DicomMessage message, IDicomServiceNode remoteAEInfo) { string studyInstanceUid = message.DataSet[DicomTags.StudyInstanceUid].GetString(0, string.Empty); string seriesInstanceUid = message.DataSet[DicomTags.SeriesInstanceUid].GetString(0, string.Empty); var sopInstanceUids = (string[])message.DataSet[DicomTags.SopInstanceUid].Values; lock (_syncLock) { using (var context = new DataAccessContext()) { var s = context.GetStudyStoreQuery().StudyQuery(new StudyRootStudyIdentifier {StudyInstanceUid = studyInstanceUid}); var identifier = CollectionUtils.FirstElement(s); var client = new DicomSendBridge(); client.SendSops(remoteAEInfo, identifier, seriesInstanceUid, sopInstanceUids, WorkItemPriorityEnum.High); _sendOperations.Add(new SendOperationInfo(client.WorkItem, message.MessageId, presentationID, server) { SubOperations = sopInstanceUids.Length }); } } }
/// <summary> /// Method for processing Study level queries. /// </summary> /// <param name="server"></param> /// <param name="presentationId"></param> /// <param name="message"></param> /// <returns></returns> private void OnReceiveStudyLevelQuery(DicomServer server, byte presentationId, DicomMessage message) { var tagList = new List<DicomTag>(); using (IReadContext read = PersistentStoreRegistry.GetDefaultStore().OpenReadContext()) { var find = read.GetBroker<IStudyEntityBroker>(); var criteria = new StudySelectCriteria(); criteria.ServerPartitionKey.EqualTo(Partition.GetKey()); DicomAttributeCollection data = message.DataSet; foreach (DicomAttribute attrib in message.DataSet) { tagList.Add(attrib.Tag); if (!attrib.IsNull) switch (attrib.Tag.TagValue) { case DicomTags.StudyInstanceUid: QueryHelper.SetStringArrayCondition(criteria.StudyInstanceUid, (string[]) data[DicomTags.StudyInstanceUid].Values); break; case DicomTags.PatientsName: QueryHelper.SetStringCondition(criteria.PatientsName, data[DicomTags.PatientsName].GetString(0, string.Empty)); break; case DicomTags.PatientId: QueryHelper.SetStringCondition(criteria.PatientId, data[DicomTags.PatientId].GetString(0, string.Empty)); break; case DicomTags.PatientsBirthDate: QueryHelper.SetRangeCondition(criteria.PatientsBirthDate, data[DicomTags.PatientsBirthDate].GetString(0, string.Empty)); break; case DicomTags.PatientsSex: QueryHelper.SetStringCondition(criteria.PatientsSex, data[DicomTags.PatientsSex].GetString(0, string.Empty)); break; case DicomTags.StudyDate: QueryHelper.SetRangeCondition(criteria.StudyDate, data[DicomTags.StudyDate].GetString(0, string.Empty)); break; case DicomTags.StudyTime: QueryHelper.SetRangeCondition(criteria.StudyTime, data[DicomTags.StudyTime].GetString(0, string.Empty)); break; case DicomTags.AccessionNumber: QueryHelper.SetStringCondition(criteria.AccessionNumber, data[DicomTags.AccessionNumber].GetString(0, string.Empty)); break; case DicomTags.StudyId: QueryHelper.SetStringCondition(criteria.StudyId, data[DicomTags.StudyId].GetString(0, string.Empty)); break; case DicomTags.StudyDescription: QueryHelper.SetStringCondition(criteria.StudyDescription, data[DicomTags.StudyDescription].GetString(0, string.Empty)); break; case DicomTags.ReferringPhysiciansName: QueryHelper.SetStringCondition(criteria.ReferringPhysiciansName, data[DicomTags.ReferringPhysiciansName].GetString(0, string.Empty)); break; case DicomTags.ModalitiesInStudy: // Specify a subselect on Modality in series var seriesSelect = new SeriesSelectCriteria(); QueryHelper.SetStringArrayCondition(seriesSelect.Modality, (string[]) data[DicomTags.ModalitiesInStudy].Values); criteria.SeriesRelatedEntityCondition.Exists(seriesSelect); break; default: foreach (var q in _queryExtensions) q.OnReceiveStudyLevelQuery(message, attrib.Tag, criteria); break; } } int resultCount = 0; try { // Open another read context, in case additional queries are required. using (IReadContext subRead = PersistentStoreRegistry.GetDefaultStore().OpenReadContext()) { // First find the Online studies var storageCriteria = new StudyStorageSelectCriteria(); storageCriteria.StudyStatusEnum.NotEqualTo(StudyStatusEnum.Nearline); storageCriteria.QueueStudyStateEnum.NotIn(new[] {QueueStudyStateEnum.DeleteScheduled, QueueStudyStateEnum.WebDeleteScheduled, QueueStudyStateEnum.EditScheduled}); criteria.StudyStorageRelatedEntityCondition.Exists(storageCriteria); find.Find(criteria, delegate(Study row) { if (CancelReceived) throw new DicomException("DICOM C-Cancel Received"); resultCount++; if (DicomSettings.Default.MaxQueryResponses != -1 && DicomSettings.Default.MaxQueryResponses < resultCount) { SendBufferedResponses(server, presentationId, message); throw new DicomException("Maximum Configured Query Responses Exceeded: " + resultCount); } var response = new DicomMessage(); PopulateStudy(subRead, response, tagList, row, "ONLINE"); _responseQueue.Enqueue(response); if (_responseQueue.Count >= DicomSettings.Default.BufferedQueryResponses) SendBufferedResponses(server, presentationId, message); }); // Now find the Nearline studies storageCriteria = new StudyStorageSelectCriteria(); storageCriteria.StudyStatusEnum.EqualTo(StudyStatusEnum.Nearline); storageCriteria.QueueStudyStateEnum.NotIn(new[] { QueueStudyStateEnum.DeleteScheduled, QueueStudyStateEnum.WebDeleteScheduled, QueueStudyStateEnum.EditScheduled }); criteria.StudyStorageRelatedEntityCondition.Exists(storageCriteria); find.Find(criteria, delegate(Study row) { if (CancelReceived) throw new DicomException("DICOM C-Cancel Received"); resultCount++; if (DicomSettings.Default.MaxQueryResponses != -1 && DicomSettings.Default.MaxQueryResponses < resultCount) { SendBufferedResponses(server, presentationId, message); throw new DicomException("Maximum Configured Query Responses Exceeded: " + resultCount); } var response = new DicomMessage(); PopulateStudy(subRead, response, tagList, row, "NEARLINE"); _responseQueue.Enqueue(response); if (_responseQueue.Count >= DicomSettings.Default.BufferedQueryResponses) SendBufferedResponses(server, presentationId, message); }); SendBufferedResponses(server, presentationId, message); } } catch (Exception e) { if (CancelReceived) { var errorResponse = new DicomMessage(); server.SendCFindResponse(presentationId, message.MessageId, errorResponse, DicomStatuses.Cancel); AuditLog(server.AssociationParams, EventIdentificationContentsEventOutcomeIndicator.Success, message); } else if (DicomSettings.Default.MaxQueryResponses != -1 && DicomSettings.Default.MaxQueryResponses < resultCount) { Platform.Log(LogLevel.Warn, "Maximum Configured Query Responses Exceeded: {0} on query from {1}", resultCount, server.AssociationParams.CallingAE); var errorResponse = new DicomMessage(); server.SendCFindResponse(presentationId, message.MessageId, errorResponse, DicomStatuses.Success); AuditLog(server.AssociationParams, EventIdentificationContentsEventOutcomeIndicator.Success, message); } else { Platform.Log(LogLevel.Error, e, "Unexpected exception when processing FIND request."); var errorResponse = new DicomMessage(); server.SendCFindResponse(presentationId, message.MessageId, errorResponse, DicomStatuses.ProcessingFailure); AuditLog(server.AssociationParams, EventIdentificationContentsEventOutcomeIndicator.SeriousFailureActionTerminated, message); } return; } } var finalResponse = new DicomMessage(); server.SendCFindResponse(presentationId, message.MessageId, finalResponse, DicomStatuses.Success); AuditLog(server.AssociationParams, EventIdentificationContentsEventOutcomeIndicator.Success, message); return; }
public override bool OnReceiveRequest(ClearCanvas.Dicom.Network.DicomServer server, ServerAssociationParameters association, byte presentationID, DicomMessage message) { //// Check for a Cancel message, and cancel the SCU. if (message.CommandField == DicomCommandField.CCancelRequest) { OnReceiveCancelRequest(message); return true; } // TODO (CR Jun 2012): Log when there's more than 1. var remoteAE = ServerDirectory.GetRemoteServersByAETitle(message.MoveDestination).FirstOrDefault(); if (remoteAE == null) { server.SendCMoveResponse(presentationID, message.MessageId, new DicomMessage(), DicomStatuses.QueryRetrieveMoveDestinationUnknown); return true; } String level = message.DataSet[DicomTags.QueryRetrieveLevel].GetString(0, string.Empty); try { if (level.Equals("STUDY")) { OnReceiveMoveStudiesRequest(server, presentationID, message, remoteAE); } else if (level.Equals("SERIES")) { OnReceiveMoveSeriesRequest(server, presentationID, message, remoteAE); } else if (level.Equals("IMAGE")) { OnReceiveMoveImageRequest(server, presentationID, message, remoteAE); } else { Platform.Log(LogLevel.Error, "Unexpected Study Root Move Query/Retrieve level: {0}", level); server.SendCMoveResponse(presentationID, message.MessageId, new DicomMessage(), DicomStatuses.QueryRetrieveIdentifierDoesNotMatchSOPClass); return true; } } catch(Exception e) { Platform.Log(LogLevel.Error, e, "Unexpected exception when processing C-MOVE-RQ"); try { server.SendCMoveResponse(presentationID, message.MessageId, new DicomMessage(), DicomStatuses.QueryRetrieveUnableToProcess, e.Message); } catch (Exception ex) { Platform.Log(LogLevel.Error, ex, "Unable to send final C-MOVE-RSP message on association from {0} to {1}", association.CallingAE, association.CalledAE); } } return true; }
/// <summary> /// Method for processing Series level queries. /// </summary> /// <param name="server"></param> /// <param name="presentationId"></param> /// <param name="message"></param> /// <returns></returns> private void OnReceiveSeriesLevelQuery(DicomServer server, byte presentationId, DicomMessage message) { //Read context for the query. using (IReadContext read = PersistentStoreRegistry.GetDefaultStore().OpenReadContext()) { var tagList = new List<DicomTag>(); var selectSeries = read.GetBroker<ISeriesEntityBroker>(); var criteria = new SeriesSelectCriteria(); criteria.ServerPartitionKey.EqualTo(Partition.GetKey()); DicomAttributeCollection data = message.DataSet; foreach (DicomAttribute attrib in message.DataSet) { tagList.Add(attrib.Tag); if (!attrib.IsNull) switch (attrib.Tag.TagValue) { case DicomTags.StudyInstanceUid: List<ServerEntityKey> list = LoadStudyKey(read, (string[]) data[DicomTags.StudyInstanceUid].Values); if (list.Count == 0) { server.SendCFindResponse(presentationId, message.MessageId, new DicomMessage(), DicomStatuses.Success); AuditLog(server.AssociationParams, EventIdentificationContentsEventOutcomeIndicator.Success, message); return; } QueryHelper.SetKeyCondition(criteria.StudyKey, list.ToArray()); break; case DicomTags.SeriesInstanceUid: QueryHelper.SetStringArrayCondition(criteria.SeriesInstanceUid, (string[]) data[DicomTags.SeriesInstanceUid].Values); break; case DicomTags.Modality: QueryHelper.SetStringCondition(criteria.Modality, data[DicomTags.Modality].GetString(0, string.Empty)); break; case DicomTags.SeriesNumber: QueryHelper.SetStringCondition(criteria.SeriesNumber, data[DicomTags.SeriesNumber].GetString(0, string.Empty)); break; case DicomTags.SeriesDescription: QueryHelper.SetStringCondition(criteria.SeriesDescription, data[DicomTags.SeriesDescription].GetString(0, string.Empty)); break; case DicomTags.PerformedProcedureStepStartDate: QueryHelper.SetRangeCondition(criteria.PerformedProcedureStepStartDate, data[DicomTags.PerformedProcedureStepStartDate].GetString(0, string.Empty)); break; case DicomTags.PerformedProcedureStepStartTime: QueryHelper.SetRangeCondition(criteria.PerformedProcedureStepStartTime, data[DicomTags.PerformedProcedureStepStartTime].GetString(0, string.Empty)); break; case DicomTags.RequestAttributesSequence: // todo break; default: foreach (var q in _queryExtensions) q.OnReceiveSeriesLevelQuery(message, attrib.Tag, criteria); break; } } int resultCount = 0; try { // Open a second read context, in case other queries are required. using (IReadContext subRead = PersistentStoreRegistry.GetDefaultStore().OpenReadContext()) { selectSeries.Find(criteria, delegate(Series row) { if (CancelReceived) throw new DicomException("DICOM C-Cancel Received"); resultCount++; if (DicomSettings.Default.MaxQueryResponses != -1 && DicomSettings.Default.MaxQueryResponses < resultCount) { SendBufferedResponses(server, presentationId, message); throw new DicomException("Maximum Configured Query Responses Exceeded: " + resultCount); } var response = new DicomMessage(); PopulateSeries(subRead, message, response, tagList, row); _responseQueue.Enqueue(response); if (_responseQueue.Count >= DicomSettings.Default.BufferedQueryResponses) SendBufferedResponses(server, presentationId, message); }); SendBufferedResponses(server, presentationId, message); } } catch (Exception e) { if (CancelReceived) { var errorResponse = new DicomMessage(); server.SendCFindResponse(presentationId, message.MessageId, errorResponse, DicomStatuses.Cancel); AuditLog(server.AssociationParams, EventIdentificationContentsEventOutcomeIndicator.Success, message); } else if (DicomSettings.Default.MaxQueryResponses != -1 && DicomSettings.Default.MaxQueryResponses < resultCount) { Platform.Log(LogLevel.Warn, "Maximum Configured Query Responses Exceeded: {0} on query from {1}",resultCount,server.AssociationParams.CallingAE); var errorResponse = new DicomMessage(); server.SendCFindResponse(presentationId, message.MessageId, errorResponse, DicomStatuses.Success); AuditLog(server.AssociationParams, EventIdentificationContentsEventOutcomeIndicator.Success, message); } else { Platform.Log(LogLevel.Error, e, "Unexpected exception when processing FIND request."); var errorResponse = new DicomMessage(); server.SendCFindResponse(presentationId, message.MessageId, errorResponse, DicomStatuses.ProcessingFailure); AuditLog(server.AssociationParams, EventIdentificationContentsEventOutcomeIndicator.SeriousFailureActionTerminated, message); } return; } var finalResponse = new DicomMessage(); server.SendCFindResponse(presentationId, message.MessageId, finalResponse, DicomStatuses.Success); AuditLog(server.AssociationParams, EventIdentificationContentsEventOutcomeIndicator.Success, message); return; } }