DICOM Modality Worklist (C-FIND MWL)

Section 14 of 27
52% complete

Modality Worklist enables imaging devices to retrieve their scheduled procedures from the RIS (Radiology Information System).

Understanding Modality Worklist

Modality Worklist Flowsaravanansubramanian.coman order posted to the RIS becomes a scheduled procedure the modality pulls at scan timeRIS / HISScheduler · order brokerModalityCT · MRI · Ultrasound · …1Order createdHL7 ORM/OMG or manual entryMWL Query (C-FIND)Modality Worklist Information Model - FIND2Return scheduled proceduresPending responses per SPS · final Success 0x000034Tech selects patientfrom the returned worklist5Scan performedpre-filled demographics,accession, and Study Instance UID

Worklist Query Implementation

Implementing a worklist query client allows modalities to retrieve scheduled procedures from the RIS. The query includes search criteria like date and modality, and returns matching scheduled procedure steps with all relevant patient and order information.

Basic MWL Query

The following implementation queries the worklist and parses results into a structured format. Search criteria can filter by date, modality, or scheduled station to retrieve only relevant procedures for the querying device.

public class ModalityWorklistService
{
    public List<WorklistItem> QueryWorklist(
        string callingAE,
        string calledAE,
        string host,
        int port,
        string scheduledDate = "",
        string modality = "",
        string scheduledStationAE = "")
    {
        List<WorklistItem> results = new List<WorklistItem>();

        DicomAssociation association = new DicomAssociation
        {
            CallingAETitle = callingAE,
            CalledAETitle = calledAE,
            Host = host,
            Port = port
        };

        // Add MWL presentation context
        association.AddPresentationContext(
            SOPClasses.ModalityWorklistFind,
            DicomTransferSyntax.ExplicitVRLittleEndian,
            DicomTransferSyntax.ImplicitVRLittleEndian
        );

        try
        {
            association.Open();

            // Create query dataset
            DicomDataSet query = CreateWorklistQuery(scheduledDate, modality, scheduledStationAE);

            // Create C-FIND request
            DicomCommandSet request = new DicomCommandSet(DicomCommandType.C_FIND_RQ);
            request.AffectedSOPClassUID = SOPClasses.ModalityWorklistFind;
            request.MessageID = 1;
            request.Priority = 0;

            // Send query and collect results
            DicomCommandSet response;
            DicomDataSet responseData;

            do
            {
                response = association.SendRequest(request, query, out responseData);

                if (responseData != null && response.Status == 0xFF00) // Pending
                {
                    WorklistItem item = ParseWorklistItem(responseData);
                    results.Add(item);
                    DisplayWorklistItem(item);
                }

            } while (response.Status == 0xFF00);

            if (response.Status == 0)
            {
                Console.WriteLine($"\nFound {results.Count} scheduled procedures");
            }
            else
            {
                Console.WriteLine($"Query failed: Status 0x{response.Status:X4}");
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"MWL query error: {ex.Message}");
        }
        finally
        {
            if (association.IsOpen)
            {
                association.Close();
            }
        }

        return results;
    }

    private DicomDataSet CreateWorklistQuery(
        string scheduledDate,
        string modality,
        string scheduledStationAE)
    {
        DicomDataSet query = new DicomDataSet();

        // Patient Level - Return Keys (empty values to return)
        query.Add(DicomTag.PatientName, "");
        query.Add(DicomTag.PatientID, "");
        query.Add(DicomTag.PatientBirthDate, "");
        query.Add(DicomTag.PatientSex, "");
        query.Add(DicomTag.PatientWeight, "");

        // Study Level
        query.Add(DicomTag.StudyInstanceUID, "");
        query.Add(DicomTag.AccessionNumber, "");
        query.Add(DicomTag.RequestedProcedureID, "");
        query.Add(DicomTag.RequestedProcedureDescription, "");
        query.Add(DicomTag.ReferringPhysicianName, "");

        // Scheduled Procedure Step Sequence (0040,0100)
        DicomSequence spsSequence = new DicomSequence(DicomTag.ScheduledProcedureStepSequence);
        DicomDataSet spsItem = new DicomDataSet();

        // Matching keys
        if (!string.IsNullOrEmpty(scheduledDate))
        {
            spsItem.Add(DicomTag.ScheduledProcedureStepStartDate, scheduledDate);
        }
        else
        {
            // Today's date
            spsItem.Add(DicomTag.ScheduledProcedureStepStartDate,
                DateTime.Now.ToString("yyyyMMdd"));
        }

        if (!string.IsNullOrEmpty(modality))
        {
            spsItem.Add(DicomTag.Modality, modality);
        }
        else
        {
            spsItem.Add(DicomTag.Modality, "");
        }

        if (!string.IsNullOrEmpty(scheduledStationAE))
        {
            spsItem.Add(DicomTag.ScheduledStationAETitle, scheduledStationAE);
        }
        else
        {
            spsItem.Add(DicomTag.ScheduledStationAETitle, "");
        }

        // Return keys for Scheduled Procedure Step
        spsItem.Add(DicomTag.ScheduledProcedureStepStartTime, "");
        spsItem.Add(DicomTag.ScheduledPerformingPhysicianName, "");
        spsItem.Add(DicomTag.ScheduledProcedureStepDescription, "");
        spsItem.Add(DicomTag.ScheduledProcedureStepID, "");
        spsItem.Add(DicomTag.ScheduledStationName, "");
        spsItem.Add(DicomTag.ScheduledProcedureStepLocation, "");

        spsSequence.Items.Add(spsItem);
        query.Add(spsSequence);

        return query;
    }

    private WorklistItem ParseWorklistItem(DicomDataSet ds)
    {
        var item = new WorklistItem();

        // Patient Information
        item.PatientName = ds[DicomTag.PatientName]?.Value?.ToString() ?? "";
        item.PatientID = ds[DicomTag.PatientID]?.Value?.ToString() ?? "";
        item.PatientBirthDate = ds[DicomTag.PatientBirthDate]?.Value?.ToString() ?? "";
        item.PatientSex = ds[DicomTag.PatientSex]?.Value?.ToString() ?? "";

        // Study Information
        item.StudyInstanceUID = ds[DicomTag.StudyInstanceUID]?.Value?.ToString() ?? "";
        item.AccessionNumber = ds[DicomTag.AccessionNumber]?.Value?.ToString() ?? "";
        item.RequestedProcedureID = ds[DicomTag.RequestedProcedureID]?.Value?.ToString() ?? "";
        item.RequestedProcedureDescription =
            ds[DicomTag.RequestedProcedureDescription]?.Value?.ToString() ?? "";
        item.ReferringPhysicianName =
            ds[DicomTag.ReferringPhysicianName]?.Value?.ToString() ?? "";

        // Parse Scheduled Procedure Step Sequence
        var spsSequence = ds[DicomTag.ScheduledProcedureStepSequence] as DicomSequence;
        if (spsSequence != null && spsSequence.Items.Count > 0)
        {
            var sps = spsSequence.Items[0];
            item.Modality = sps[DicomTag.Modality]?.Value?.ToString() ?? "";
            item.ScheduledAETitle = sps[DicomTag.ScheduledStationAETitle]?.Value?.ToString() ?? "";
            item.ScheduledDate = sps[DicomTag.ScheduledProcedureStepStartDate]?.Value?.ToString() ?? "";
            item.ScheduledTime = sps[DicomTag.ScheduledProcedureStepStartTime]?.Value?.ToString() ?? "";
            item.ScheduledProcedureStepID =
                sps[DicomTag.ScheduledProcedureStepID]?.Value?.ToString() ?? "";
            item.ScheduledProcedureStepDescription =
                sps[DicomTag.ScheduledProcedureStepDescription]?.Value?.ToString() ?? "";
            item.ScheduledPerformingPhysician =
                sps[DicomTag.ScheduledPerformingPhysicianName]?.Value?.ToString() ?? "";
        }

        return item;
    }

    private void DisplayWorklistItem(WorklistItem item)
    {
        Console.WriteLine("\n=== Scheduled Procedure ===");
        Console.WriteLine($"Patient: {item.PatientName} ({item.PatientID})");
        Console.WriteLine($"Birth Date: {item.PatientBirthDate}, Sex: {item.PatientSex}");
        Console.WriteLine($"Accession: {item.AccessionNumber}");
        Console.WriteLine($"Procedure: {item.RequestedProcedureDescription}");
        Console.WriteLine($"Modality: {item.Modality}");
        Console.WriteLine($"Scheduled: {item.ScheduledDate} {item.ScheduledTime}");
        Console.WriteLine($"Station: {item.ScheduledAETitle}");
        Console.WriteLine($"Referring: {item.ReferringPhysicianName}");
    }
}

public class WorklistItem
{
    // Patient Information
    public string PatientName { get; set; }
    public string PatientID { get; set; }
    public string PatientBirthDate { get; set; }
    public string PatientSex { get; set; }

    // Study Information
    public string StudyInstanceUID { get; set; }
    public string AccessionNumber { get; set; }
    public string RequestedProcedureID { get; set; }
    public string RequestedProcedureDescription { get; set; }
    public string ReferringPhysicianName { get; set; }

    // Scheduled Procedure Step Information
    public string Modality { get; set; }
    public string ScheduledAETitle { get; set; }
    public string ScheduledDate { get; set; }
    public string ScheduledTime { get; set; }
    public string ScheduledProcedureStepID { get; set; }
    public string ScheduledProcedureStepDescription { get; set; }
    public string ScheduledPerformingPhysician { get; set; }
}

Worklist Attributes

Key Attributes Summary

Modality Worklist Attributessaravanansubramanian.comevery returned worklist item is composed from three attribute groups with DICOM tagsPatient LevelPatient Name(0010,0010)Patient ID(0010,0020)Patient Birth Date(0010,0030)Patient Sex(0010,0040)Patient Weight(0010,1030)demographics used topopulate the study headerStudy / Order LevelStudy Instance UID(0020,000D)Accession Number(0008,0050)Requested Procedure ID(0040,1001)Requested Procedure Desc(0032,1060)Referring Physician(0008,0090)Requesting Physician(0032,1032)links a MWL item to its orderand, later, to the acquired imagesScheduled Procedure StepSequence (0040,0100)SPS Start Date(0040,0002)SPS Start Time(0040,0003)Modality(0008,0060)Scheduled Station AE(0040,0001)Scheduled Station Name(0040,0010)SPS Description(0040,0007)SPS ID(0040,0009)SPS Location(0040,0011)Scheduled Performing Phys.(0040,0006)Worklist Itema single MWL C-FIND response assembles all three groups above into one datasetWhy the SPS lives in a sequenceOne requested procedure may schedule multiple steps (e.g. multi-phase CT with and without contrast), each with its own station,time, and modality. Packing them into a DICOM sequence lets a single MWL item describe an entire multi-step order withoutduplicating patient and study metadata for every step.Rule of thumb: Patient + Study/Order are flat on the item; anything that varies per step goes inside the SPS Sequence.

Using Worklist Data

Once a procedure is selected from the worklist, the modality should apply the worklist data to acquired images. This ensures consistent patient demographics, proper order linkage via accession number, and pre-assigned Study Instance UIDs for PACS reconciliation.

Applying Worklist to Image Acquisition

This method copies worklist attributes to image data, ensuring images are properly linked to the original order. The Request Attributes Sequence provides explicit linkage for billing and workflow systems.

public class ModalityWorklistIntegration
{
    public DicomDataSet ApplyWorklistToImage(WorklistItem worklist, DicomDataSet imageData)
    {
        // Patient Information
        imageData[DicomTag.PatientName].Value = worklist.PatientName;
        imageData[DicomTag.PatientID].Value = worklist.PatientID;
        imageData[DicomTag.PatientBirthDate].Value = worklist.PatientBirthDate;
        imageData[DicomTag.PatientSex].Value = worklist.PatientSex;

        // Study Information - Use pre-assigned Study Instance UID from worklist!
        imageData[DicomTag.StudyInstanceUID].Value = worklist.StudyInstanceUID;
        imageData[DicomTag.AccessionNumber].Value = worklist.AccessionNumber;
        imageData[DicomTag.ReferringPhysicianName].Value = worklist.ReferringPhysicianName;
        imageData[DicomTag.StudyDescription].Value = worklist.RequestedProcedureDescription;

        // Study Date/Time - Actual acquisition time
        imageData[DicomTag.StudyDate].Value = DateTime.Now.ToString("yyyyMMdd");
        imageData[DicomTag.StudyTime].Value = DateTime.Now.ToString("HHmmss");

        // Series Information
        imageData[DicomTag.SeriesInstanceUID].Value = DicomUID.Generate();
        imageData[DicomTag.Modality].Value = worklist.Modality;
        imageData[DicomTag.SeriesDescription].Value = worklist.ScheduledProcedureStepDescription;

        // Request Attributes Sequence - Link back to order
        DicomSequence requestSeq = new DicomSequence(DicomTag.RequestAttributesSequence);
        DicomDataSet requestItem = new DicomDataSet();
        requestItem.Add(DicomTag.RequestedProcedureID, worklist.RequestedProcedureID);
        requestItem.Add(DicomTag.ScheduledProcedureStepID, worklist.ScheduledProcedureStepID);
        requestSeq.Items.Add(requestItem);
        imageData.Add(requestSeq);

        return imageData;
    }
}

Worklist Search Patterns

Different clinical scenarios require different search strategies. The following examples demonstrate common query patterns for filtering the worklist by various criteria.

// Query for today's procedures
var todayWorklist = service.QueryWorklist(
    callingAE: "CT_SCANNER",
    calledAE: "RIS_SERVER",
    host: "192.168.1.50",
    port: 104,
    scheduledDate: DateTime.Now.ToString("yyyyMMdd")
);

// Query for specific modality
var ctWorklist = service.QueryWorklist(
    callingAE: "CT_SCANNER",
    calledAE: "RIS_SERVER",
    host: "192.168.1.50",
    port: 104,
    modality: "CT"
);

// Query for specific station
var stationWorklist = service.QueryWorklist(
    callingAE: "CT_SCANNER",
    calledAE: "RIS_SERVER",
    host: "192.168.1.50",
    port: 104,
    scheduledStationAE: "CT_SCANNER_1"
);

// Query with date range (using wildcard)
var rangeWorklist = service.QueryWorklist(
    callingAE: "CT_SCANNER",
    calledAE: "RIS_SERVER",
    host: "192.168.1.50",
    port: 104,
    scheduledDate: "20240115-20240131" // Date range
);

Integration Benefits

Worklist Benefitssaravanansubramanian.comthree concerns, each dramatically simpler when the modality pulls its schedule from the RISWithout WorklistWith WorklistPatient entryManual — technologist types every fieldName typedID typedDOB typed · typos commonPatient entryAuto-populated from RISSelect patient from returned listDemographics pre-filledOrder details included · error-freeStudy / Order trackingNo link back to the order that scheduled the studyNo accession number capturedNo order linkageBilling reconciliation problemsStudy / Order trackingEvery image carries the correct order identifiersCorrect accession numberLinked back to the RIS orderProper billing and EMR reconciliationData consistencyAd-hoc formatting varies per technologistVarying date and name formatsSpelling errorsMismatched records across systemsData consistencyRIS is the single source of truthStandardized formatsCorrect, canonical spellingUnified patient record

Modality Worklist is essential for efficient, error-free radiology workflows.

Quiz: DICOM Modality Worklist (C-FIND MWL)

Question 1 of 4

What SOP Class UID is used for Modality Worklist queries?