The StoreSCPCallback example demonstrates how to use the DCF to implement a simple store SCP using a callback method
that receives datasets and writes them to disk.
Classes
Class | Description | |
---|---|---|
Program |
Basic store service class provider example which should be run with the StoreSCU.
| |
ProgramCallbackStoreServer |
CallbackStoreServer handles C-STORE requests on the associations by registering a callback that StoreSCP will call when the C-STORE request is received.
|
Examples
StoreSCPCallback Sample Code
public class Program { /// <summary> /// Main entry point for StoreSCPCallback. /// </summary> [STAThread] public static void Main() { try { // Specify a list of AllowedPresentationContext objects that will restrict what combinations of SOP class and transfer syntaxes will be allowed. IList<AllowedPresentationContext> allowed = new List<AllowedPresentationContext>(); allowed.Add(new AllowedPresentationContext(Uids.MRImageStorage, Uids.TransferSyntax.ExplicitVRLittleEndian, Uids.TransferSyntax.ImplicitVRLittleEndian)); // create a CallbackStoreServer that listens for associations on port 104 CallbackStoreServer server104 = new CallbackStoreServer(104, allowed); server104.BeginListening(); Console.WriteLine("listening on {0}...", 104); } catch (Exception e) { Console.WriteLine("Error during execution: {0}", e); Environment.ExitCode = 1; } } /// <summary> /// CallbackStoreServer handles C-STORE requests on the associations by registering a callback that StoreSCP will call when the C-STORE request is received. /// </summary> public class CallbackStoreServer : AssociationListenerAdapter, IAssociationConfigPolicyManager { readonly AssociationManager _manager; readonly IList<AllowedPresentationContext> _presentationContexts; /// <summary> /// Constructs a CallbackStoreServer that will listen on the specified port and accept the allowedPresentationContexts. /// </summary> /// <remarks> /// See <see cref="LaurelBridge.DCF.Dicom.Store.StoreSCP"/> for a description of where the default presentation contexts are retrieved. /// </remarks> /// <param name="port">The port number where we will listen for association requests</param> /// <param name="allowedPresentationContexts">The list of presentation contexts that will be allowed, or null to use defaults.</param> public CallbackStoreServer(int port, IList<AllowedPresentationContext> allowedPresentationContexts = null) { _presentationContexts = allowedPresentationContexts; _manager = new AssociationManager(); _manager.ServerTcpPort = port; _manager.AssociationConfigPolicyMgr = this; _manager.AddAssociationListener(this); } /// <summary> /// Start the AssociationManager for this server, and start listening for associations. /// </summary> public void BeginListening() { Thread t = new Thread(_manager.Run); t.Start(); if (!_manager.WaitForRunning(2000)) { throw new TimeoutException("AssociationManager did not start in an acceptable amount of time"); } } #region IAssociationConfigPolicyManager implementation /// <summary> /// Returns a DicomSessionSettings object to be used for the association. /// </summary> /// <param name="assoc">The AssociationAcceptor for the given association</param> /// <returns>A default DicomSessionSettings object</returns> public DicomSessionSettings GetSessionSettings(AssociationAcceptor assoc) { return new DicomSessionSettings(); } #endregion #region AssociationListenerAdapter overrides /// <summary> /// Override of BeginAssociation which is called during association negotiation. Register a StoreSCP object to /// handle store requests for our allowed presentation contexts by delegating to our CStore method. /// </summary> /// <param name="assoc">The AssociationAcceptor for the given association</param> public override void BeginAssociation(AssociationAcceptor assoc) { assoc.RegisterServiceClassProvider(new Dicom.Store.StoreSCP(assoc, _presentationContexts, CStore)); } #endregion /// <summary> /// Writes some information from the incoming dataset to the console. /// </summary> /// <param name="acceptor">The AssociationAcceptor for the given association</param> /// <param name="request">The inbound CStoreRequest DIMSE message</param> /// <returns>A successful CStoreResponse</returns> private CStoreResponse CStore(AssociationAcceptor acceptor, CStoreRequest request) { CStoreResponse response = new CStoreResponse(request); try { string dir = Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location) ?? "."; string filename = Path.Combine(dir, request.Data.GetElementStringValue(Tags.SOPInstanceUID) + ".dcm"); Console.WriteLine( "CallbackStoreServer: patient's name is {0} from {1} to port {2} with transfer syntax {3}. Writing to {4}{5}", request.Data.GetElementStringValue(Tags.PatientName), acceptor.AssociationInfo.CallingTitle, acceptor.AssociationInfo.CalledPresentationAddress, acceptor.AssociationInfo.GetAcceptedPresentationContext(request.ContextId).TransferSyntaxUid, filename, Environment.NewLine); // write the dataset out as a chapter 10 file to the same location as this example's executable using (DicomFileOutput dfo = new DicomFileOutput(filename, acceptor.AssociationInfo.GetAcceptedPresentationContext(request.ContextId).TransferSyntaxUid)) { // persist the AE titles from the network connection in the chapter10 file dfo.GetFileMetaInformation().SendingAETitle = acceptor.AssociationInfo.CallingTitle; dfo.GetFileMetaInformation().ReceivingAETitle = acceptor.AssociationInfo.CalledTitle; dfo.WriteDataSet(request.Data); } } catch (Exception e) { Console.WriteLine("CStore Failed: {0}", e); response.Status = DimseStatus.PROCESSING_FAILURE; response.ErrorComment = "Failed while trying to store. Error is: " + e.Message; } return response; } } }