For those who want to implement MPPS SCP, here's an older prototype with what I started. Latest version is running with modalities from Siemens(CT,MR,CR,RF,MG,US), Sectra(MG), Philips (CR,RF,CT,MR) and Carestream (CR, RF), Toshiba (CR,CT) and Fuji (CR,RF,MG).
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Threading;
using System.IO;
using System.Data;
using System.Data.OleDb;
using ClearCanvas.Dicom;
using ClearCanvas.Dicom.Network;
namespace xxxMPPSService
{
class MPPSModule : IDicomServerHandler
{
private static bool _started = false;
private static ServerAssociationParameters _staticAssocParameters;
private ServerAssociationParameters _assocParameters;
private static void AddPresentationContexts(ServerAssociationParameters assoc)
{
byte pcid = assoc.AddPresentationContext(SopClass.VerificationSopClass);
assoc.AddTransferSyntax(pcid, TransferSyntax.ExplicitVrLittleEndian);
assoc.AddTransferSyntax(pcid, TransferSyntax.ImplicitVrLittleEndian);
assoc.AddTransferSyntax(pcid, TransferSyntax.ExplicitVrBigEndian);
pcid = assoc.AddPresentationContext(SopClass.ModalityPerformedProcedureStepSopClass);
assoc.AddTransferSyntax(pcid, TransferSyntax.ExplicitVrLittleEndian);
assoc.AddTransferSyntax(pcid, TransferSyntax.ImplicitVrLittleEndian);
assoc.AddTransferSyntax(pcid, TransferSyntax.ExplicitVrBigEndian);
pcid = assoc.AddPresentationContext(SopClass.ModalityWorklistInformationModelFind);
assoc.AddTransferSyntax(pcid, TransferSyntax.ExplicitVrLittleEndian);
assoc.AddTransferSyntax(pcid, TransferSyntax.ImplicitVrLittleEndian);
assoc.AddTransferSyntax(pcid, TransferSyntax.ExplicitVrBigEndian);
pcid = assoc.AddPresentationContext(SopClass.ModalityPerformedProcedureStepNotificationSopClass);
assoc.AddTransferSyntax(pcid, TransferSyntax.ExplicitVrLittleEndian);
assoc.AddTransferSyntax(pcid, TransferSyntax.ImplicitVrLittleEndian);
pcid = assoc.AddPresentationContext(SopClass.ModalityPerformedProcedureStepRetrieveSopClass);
assoc.AddTransferSyntax(pcid, TransferSyntax.ExplicitVrLittleEndian);
assoc.AddTransferSyntax(pcid, TransferSyntax.ImplicitVrLittleEndian);
}
private MPPSModule(ServerAssociationParameters assoc)
{
_assocParameters = assoc;
}
public static void StartListening(string aeTitle, int port)
{
try
{
if (_started)
return;
_staticAssocParameters = new ServerAssociationParameters(aeTitle, new IPEndPoint(IPAddress.Any, port));
AddPresentationContexts(_staticAssocParameters);
DicomServer.StartListening(_staticAssocParameters,
delegate(DicomServer server, ServerAssociationParameters assoc)
{
return new MPPSModule(assoc);
});
_started = true;
}
catch(Exception ex)
{
MPPSEventlogger.log(ex.ToString());
}
}
public static void StopListening()
{
if (_started)
{
DicomServer.StopListening(_staticAssocParameters);
_started = false;
}
}
void IDicomServerHandler.OnReceiveAssociateRequest(DicomServer server, ServerAssociationParameters association)
{
server.SendAssociateAccept(association);
}
void IDicomServerHandler.OnReceiveRequestMessage(DicomServer server, ServerAssociationParameters association, byte presentationID, DicomMessage message)
{
try
{
MPPSEventlogger.logDatabase("P", "begin OnReceiveRequestMessage");
if (message.CommandField == DicomCommandField.CEchoRequest)
{
server.SendCEchoResponse(presentationID, message.MessageId, DicomStatuses.Success);
return;
}
try
{
if (message.CommandField == DicomCommandField.NCreateRequest)
{
DicomMessage msgResp = new DicomMessage();
msgResp.MessageIdBeingRespondedTo = message.MessageId;
msgResp.CommandField = message.CommandField;
msgResp.DataSetType = message.DataSetType;
msgResp.Status = message.Status;
msgResp.DataSet[DicomTags.AffectedSopClassUid] = message.DataSet[DicomTags.AffectedSopClassUid];
server.SendNCreateResponse(presentationID, message.MessageId,
msgResp,
DicomStatuses.Success);
}
else
{
DicomMessage msgResp = new DicomMessage();
msgResp.MessageIdBeingRespondedTo = message.MessageId;
msgResp.CommandField = message.CommandField;
msgResp.DataSetType = message.DataSetType;
msgResp.Status = message.Status;
msgResp.DataSet[DicomTags.AffectedSopClassUid] = message.DataSet[DicomTags.AffectedSopClassUid];
server.SendNSetResponse(presentationID, message.MessageId,
msgResp,
DicomStatuses.Success);
}
try
{
processMessage(message);
}
catch (Exception ex)
{
}
}
catch (Exception ex)
{
}
}
catch (Exception ex)
{
}
}
void IDicomServerHandler.OnReceiveResponseMessage(DicomServer server, ServerAssociationParameters association, byte presentationID, DicomMessage message)
{
server.SendAssociateAbort(DicomAbortSource.ServiceUser, DicomAbortReason.UnrecognizedPDU);
}
void IDicomServerHandler.OnReceiveReleaseRequest(DicomServer server, ServerAssociationParameters association)
{
}
void IDicomServerHandler.OnReceiveAbort(DicomServer server, ServerAssociationParameters association, DicomAbortSource source, DicomAbortReason reason)
{
}
void IDicomServerHandler.OnNetworkError(DicomServer server, ServerAssociationParameters association, Exception e)
{
}
void IDicomServerHandler.OnDimseTimeout(DicomServer server, ServerAssociationParameters association)
{
}
protected void LogAssociationStatistics(ServerAssociationParameters association)
{
}
void processMessage(DicomMessage dcmFile)
{
if (dcmFile.DataSet[DicomTags.PerformedProcedureStepStatus].ToString().ToUpper() == "COMPLETED")
{
try
{
string sReferencedSopInstanceUid = null;
sReferencedSopInstanceUid = dcmFile.MetaInfo[DicomTags.AffectedSopInstanceUid].ToString();
//this is the same uid from "IN PROGRESS" message RequestedSopInstanceUid
}
catch (Exception ex)
{
MPPSEventlogger.log(ex.ToString() + ex.StackTrace);
}
}
else if(dcmFile.DataSet[DicomTags.PerformedProcedureStepStatus].ToString().ToUpper() == "IN PROGRESS")
{
sSopInstanceUid = dcmFile.MetaInfo[DicomTags.RequestedSopInstanceUid].ToString();
//sopinsanceuid of metadata references to the AffectedSopInstanceUID of completed/discontinued message. Accno and/or Studyuid are only sent in "IN PROGRESS" Messages.
}
}
}
}