123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251 |
- // Copyright (c) 2012-2020 fo-dicom contributors.
- // Licensed under the Microsoft Public License (MS-PL).
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
- using Dicom;
- using Dicom.Log;
- using Dicom.Network;
- using Worklist_SCP.Model;
- using System.Configuration;
- namespace Worklist_SCP
- {
- public class WorklistService : DicomService, IDicomServiceProvider, IDicomCEchoProvider, IDicomCFindProvider, IDicomNServiceProvider
- {
- private static readonly DicomTransferSyntax[] AcceptedTransferSyntaxes = new DicomTransferSyntax[]
- {
- DicomTransferSyntax.ExplicitVRLittleEndian,
- DicomTransferSyntax.ExplicitVRBigEndian,
- DicomTransferSyntax.ImplicitVRLittleEndian
- };
- private IMppsSource _mppsSource;
- private IMppsSource MppsSource
- {
- get
- {
- if (_mppsSource == null)
- {
- _mppsSource = new MppsHandler(Logger);
- }
- return _mppsSource;
- }
- }
- public WorklistService(INetworkStream stream, Encoding fallbackEncoding, Logger log) : base(stream, fallbackEncoding, log)
- {
- }
- public DicomCEchoResponse OnCEchoRequest(DicomCEchoRequest request)
- {
- Logger.Info($"Received verification request from AE {Association.CallingAE} with IP: {Association.RemoteHost}");
- return new DicomCEchoResponse(request, DicomStatus.Success);
- }
- public IEnumerable<DicomCFindResponse> OnCFindRequest(DicomCFindRequest request)
- {
- // you should validate the level of the request. I leave it here since there is a bug in version 3.0.2
- // from version 4 on this should be done
- //if (request.Level != DicomQueryRetrieveLevel.Worklist)
- //{
- // yield return new DicomCFindResponse(request, DicomStatus.QueryRetrieveUnableToProcess);
- //}
- //else
- //{
- var configType = ConfigurationManager.AppSettings["Type"];
- IEnumerable<DicomDataset> exams = null;
- Console.Write($"configType: {configType}");
- switch (configType)
- {
- case "API":
- exams = WorklistApiHandler.FilterWorklistItems(request.Dataset);
- break;
- case "JSON":
- exams = WorklistJsonHandler.FilterWorklistItems(request.Dataset);
- break;
- case "SQLServer":
- exams = WorklistSQLServerHandler.FilterWorklistItems(request.Dataset);
- break;
- case "DB":
- break;
- default:
- exams = WorklistHandler.FilterWorklistItems(request.Dataset, new WorklistItemsProvider().GetAllCurrentWorklistItems());
- break;
- }
- //var exams = WorklistApiHandler.FilterWorklistItems(request.Dataset, WorklistServer.CurrentWorklistItems);
- foreach (DicomDataset result in exams)
- //foreach (DicomDataset result in WorklistHandler.FilterWorklistItems(request.Dataset, WorklistServer.CurrentWorklistItems))
- {
- yield return new DicomCFindResponse(request, DicomStatus.Pending) { Dataset = result };
- }
- yield return new DicomCFindResponse(request, DicomStatus.Success);
- //}
- }
- public void OnConnectionClosed(Exception exception)
- {
- Clean();
- }
- public void OnReceiveAbort(DicomAbortSource source, DicomAbortReason reason)
- {
- //log the abort reason
- Logger.Error($"Received abort from {source}, reason is {reason}");
- }
- public Task OnReceiveAssociationReleaseRequestAsync()
- {
- Clean();
- return SendAssociationReleaseResponseAsync();
- }
- public Task OnReceiveAssociationRequestAsync(DicomAssociation association)
- {
- Logger.Info($"Received association request from AE: {association.CallingAE} with IP: {association.RemoteHost} ");
- //if (WorklistServer.AETitle != association.CalledAE)
- //{
- // Logger.Error($"Association with {association.CallingAE} rejected since called aet {association.CalledAE} is unknown");
- // return SendAssociationRejectAsync(DicomRejectResult.Permanent, DicomRejectSource.ServiceUser, DicomRejectReason.CalledAENotRecognized);
- //}
- foreach (var pc in association.PresentationContexts)
- {
- if (pc.AbstractSyntax == DicomUID.Verification
- || pc.AbstractSyntax == DicomUID.ModalityWorklistInformationModelFIND
- || pc.AbstractSyntax == DicomUID.ModalityPerformedProcedureStepSOPClass
- || pc.AbstractSyntax == DicomUID.ModalityPerformedProcedureStepNotificationSOPClass
- || pc.AbstractSyntax == DicomUID.ModalityPerformedProcedureStepNotificationSOPClass)
- {
- pc.AcceptTransferSyntaxes(AcceptedTransferSyntaxes);
- }
- else
- {
- Logger.Warn($"Requested abstract syntax {pc.AbstractSyntax} from {association.CallingAE} not supported");
- pc.SetResult(DicomPresentationContextResult.RejectAbstractSyntaxNotSupported);
- }
- }
- Logger.Info($"Accepted association request from {association.CallingAE}");
- return SendAssociationAcceptAsync(association);
- }
- public void Clean()
- {
- // cleanup, like cancel outstanding move- or get-jobs
- }
- public DicomNCreateResponse OnNCreateRequest(DicomNCreateRequest request)
- {
- if (request.SOPClassUID != DicomUID.ModalityPerformedProcedureStepSOPClass)
- {
- return new DicomNCreateResponse(request, DicomStatus.SOPClassNotSupported);
- }
- // on N-Create the UID is stored in AffectedSopInstanceUID, in N-Set the UID is stored in RequestedSopInstanceUID
- var affectedSopInstanceUID = request.Command.GetSingleValue<string>(DicomTag.AffectedSOPInstanceUID);
- Logger.Log(LogLevel.Info, $"reeiving N-Create with SOPUID {affectedSopInstanceUID}");
- // get the procedureStepIds from the request
- var procedureStepId = request.Dataset
- .GetSequence(DicomTag.ScheduledStepAttributesSequence)
- .First()
- .GetSingleValue<string>(DicomTag.ScheduledProcedureStepID);
- var ok = MppsSource.SetInProgress(affectedSopInstanceUID, procedureStepId);
- return new DicomNCreateResponse(request, ok ? DicomStatus.Success : DicomStatus.ProcessingFailure);
- }
- public DicomNSetResponse OnNSetRequest(DicomNSetRequest request)
- {
- if (request.SOPClassUID != DicomUID.ModalityPerformedProcedureStepSOPClass)
- {
- return new DicomNSetResponse(request, DicomStatus.SOPClassNotSupported);
- }
- // on N-Create the UID is stored in AffectedSopInstanceUID, in N-Set the UID is stored in RequestedSopInstanceUID
- var requestedSopInstanceUID = request.Command.GetSingleValue<string>(DicomTag.RequestedSOPInstanceUID);
- Logger.Log(LogLevel.Info, $"receiving N-Set with SOPUID {requestedSopInstanceUID}");
- var status = request.Dataset.GetSingleValue<string>(DicomTag.PerformedProcedureStepStatus);
- if (status == "COMPLETED")
- {
- // most vendors send some informations with the mpps-completed message.
- // this information should be stored into the datbase
- var doseDescription = request.Dataset.GetSingleValueOrDefault(DicomTag.CommentsOnRadiationDose, string.Empty);
- var listOfInstanceUIDs = new List<string>();
- foreach (var seriesDataset in request.Dataset.GetSequence(DicomTag.PerformedSeriesSequence))
- {
- // you can read here some information about the series that the modalidy created
- //seriesDataset.Get(DicomTag.SeriesDescription, string.Empty);
- //seriesDataset.Get(DicomTag.PerformingPhysicianName, string.Empty);
- //seriesDataset.Get(DicomTag.ProtocolName, string.Empty);
- foreach (var instanceDataset in seriesDataset.GetSequence(DicomTag.ReferencedImageSequence))
- {
- // here you can read the SOPClassUID and SOPInstanceUID
- var instanceUID = instanceDataset.GetSingleValueOrDefault(DicomTag.ReferencedSOPInstanceUID, string.Empty);
- if (!string.IsNullOrEmpty(instanceUID)) listOfInstanceUIDs.Add(instanceUID);
- }
- }
- var ok = MppsSource.SetCompleted(requestedSopInstanceUID, doseDescription, listOfInstanceUIDs);
- return new DicomNSetResponse(request, ok ? DicomStatus.Success : DicomStatus.ProcessingFailure);
- }
- else if (status == "DISCONTINUED")
- {
- // some vendors send a reason code or description with the mpps-discontinued message
- // var reason = request.Dataset.Get(DicomTag.PerformedProcedureStepDiscontinuationReasonCodeSequence);
- var ok = MppsSource.SetDiscontinued(requestedSopInstanceUID, string.Empty);
- return new DicomNSetResponse(request, ok ? DicomStatus.Success : DicomStatus.ProcessingFailure);
- }
- else
- {
- return new DicomNSetResponse(request, DicomStatus.InvalidAttributeValue);
- }
- }
- #region not supported methods but that are required because of the interface
- public DicomNDeleteResponse OnNDeleteRequest(DicomNDeleteRequest request)
- {
- Logger.Log(LogLevel.Info, "receiving N-Delete, not supported");
- return new DicomNDeleteResponse(request, DicomStatus.UnrecognizedOperation);
- }
- public DicomNEventReportResponse OnNEventReportRequest(DicomNEventReportRequest request)
- {
- Logger.Log(LogLevel.Info, "receiving N-Event, not supported");
- return new DicomNEventReportResponse(request, DicomStatus.UnrecognizedOperation);
- }
- public DicomNGetResponse OnNGetRequest(DicomNGetRequest request)
- {
- Logger.Log(LogLevel.Info, "receiving N-Get, not supported");
- return new DicomNGetResponse(request, DicomStatus.UnrecognizedOperation);
- }
- public DicomNActionResponse OnNActionRequest(DicomNActionRequest request)
- {
- Logger.Log(LogLevel.Info, "receiving N-Action, not supported");
- return new DicomNActionResponse(request, DicomStatus.UnrecognizedOperation);
- }
- #endregion
- }
- }
|