Modality Worklist enables imaging devices to retrieve their scheduled procedures from the RIS (Radiology Information System).
Understanding Modality Worklist
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
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
Modality Worklist is essential for efficient, error-free radiology workflows.