LAUREL BRIDGE

LaurelBridge.DCF.Examples.StoreSCPCallback Namespace

DICOM Connectivity Framework V3.4
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

  ClassDescription
Public classProgram
Basic store service class provider example which should be run with the StoreSCU.
Public classProgramCallbackStoreServer
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>
    /// <param name="args">Program arguments.</param>
    [STAThread]
    public static void Main(string[] args)
    {
        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;
        }
    }
}