DICOMweb Client
DICOMweb client
DicomWebClient is an HTTP user agent independent of the server application in this library. Give it an application-configured HttpClient and DicomWebClientOptions with an absolute BaseUri pointing at the remote service root. The client does not own or dispose the HttpClient. Configure authentication, TLS, proxy, redirects, and connection pooling on that transport. ServiceBaseUris can override roots by DicomWebService when a deployment splits services across paths or origins. BulkDataLoader supplies external metadata Bulk Data resolution; MaxNotificationMessageBytes defaults to 16 MiB.
| Option | Default and valid values | Effect |
|---|---|---|
BaseUri |
Required absolute HTTP or HTTPS URI | Default root for every operation group. |
ServiceBaseUris |
Empty immutable dictionary; each override must be an absolute HTTP or HTTPS URI | Overrides one DicomWebService root. |
MaxNotificationMessageBytes |
16 MiB; positive integer | Rejects larger incoming WebSocket event reports. |
BulkDataLoader |
null |
Optional IAsyncBulkDataLoader used while parsing external metadata Bulk Data. |
Supply service roots without query strings or fragments. The client appends each standard resource path to the selected root and escapes route and query values; pass those values decoded. A root of https://example.org/dicomweb/ produces a Studies search at https://example.org/dicomweb/studies, while WADO-URI sends its identifying query parameters to the root itself.
using System.Net.Http.HttpClient transport = new();
Aspose.Medical.Dicom.Web.DicomWebClient client = new(transport,
new DicomWebClientOptions
{
BaseUri = new System.Uri("https://example.org/dicomweb/")
});
await using Aspose.Medical.Dicom.Web.DicomWebClientStream<Aspose.Medical.Dicom.Dataset> studies =
await client.Studies.SearchAsync(new DicomWebSearchOptions { Limit = 20 });
await foreach (Aspose.Medical.Dicom.Dataset study in studies)
System.Console.WriteLine(study.Count);
DicomWebSearchOptions supplies ordered matching parameters, included fields, Limit, Offset, fuzzy, empty-value, and multiple-value matching flags, accepted media types, and extra headers. Null option values omit the corresponding query control. Searches return DicomWebClientStream<Dataset>, which owns a live response, can be enumerated once, and should be disposed even if enumeration stops early. DicomWebRetrieveOptions carries accepted media types, extra query parameters, and headers. DicomWebRenderOptions adds quality (1–100), viewport, window, ICC profile, annotation tokens, and additional parameters; see rendering control formats and thumbnail differences. DicomWebRequestOptions carries query parameters and headers for body operations. An empty AcceptedMediaTypes uses the transaction default; do not set both it and an explicit Accept header.
Set MatchingParameters to repeated, decoded DicomWebQueryParameter values. IncludeFields requests additional projected attributes; EmptyValueMatching, FuzzyMatching, and MultipleValueMatching are nullable so an omitted value leaves the server default in place. The provider receives a compiled search plan and the standard engine performs final DICOM matching:
using System.Net.Http.HttpClient transport = new();
Aspose.Medical.Dicom.Web.DicomWebClient client = new(transport,
new DicomWebClientOptions
{
BaseUri = new System.Uri("https://example.org/dicomweb/")
});
Aspose.Medical.Dicom.Web.DicomWebSearchOptions options = new()
{
MatchingParameters = [new Aspose.Medical.Dicom.Web.DicomWebQueryParameter("PatientName", "SMITH*")],
IncludeFields = ["StudyDate", "PatientID"],
FuzzyMatching = false,
EmptyValueMatching = false,
MultipleValueMatching = false,
Limit = 20,
Offset = 0
};
await using Aspose.Medical.Dicom.Web.DicomWebClientStream<Aspose.Medical.Dicom.Dataset> matches =
await client.Studies.SearchAsync(options);
await foreach (Aspose.Medical.Dicom.Dataset study in matches)
System.Console.WriteLine(study.Count);
When explicitly including a private data attribute in a standard study, series, instance, or workitem search, also supply a matching parameter for its Private Creator attribute. The creator must identify the same private block and, for a nested attribute, have the same sequence path. The standard service rejects an included private data attribute without its corresponding creator match. This requirement does not apply to including the Private Creator attribute itself.
Operation groups and results
| Client property | Operations | Result shape |
|---|---|---|
Capabilities |
RetrieveAsync |
Raw DicomWebClientResponse for JSON or WADL capabilities |
Uri |
RetrieveDicomInstanceAsync, RetrieveRenderedInstanceAsync |
Materialized RetrieveUriDicomInstanceResult.File, or raw rendered response |
Studies |
Study/series/instance search; StoreAsync and StoreStudyAsync; study/series/instance DICOM and metadata retrieval; bulk data, pixel data, frame retrieval; rendered, MPR, 3D, and thumbnail retrieval |
Search/metadata DicomWebClientStream<Dataset>; study/series DicomWebClientStream<DicomFile>; single instance RetrieveInstanceResult.File; store StoreInstancesResult.Response; binary/rendered methods return raw responses |
Worklist |
Create, search, retrieve, update, change state, request cancellation, workitem/worklist/filtered-worklist subscription changes, ConnectNotificationsAsync |
Workitem datasets, optional status reports, materialized outcomes, search stream, or notification connection |
StorageCommitment |
RequestAsync, CheckResultAsync |
IsPending and optional Report |
ModalityWorklist |
SearchAsync |
Dataset stream |
ModalityPerformedProcedureSteps |
CreateAsync, UpdateAsync, RetrieveAsync |
Optional status report or retrieved procedure-step dataset |
NonPatientInstances |
SearchAsync, StoreAsync, RetrieveAsync |
Dataset stream, STOW response dataset, or RetrieveNonPatientInstanceResult.File |
The method overloads accept a typed Dataset or DicomFile for common requests and DicomWebContent for caller-controlled payloads. Studies and non-patient stores also accept synchronous or asynchronous file sequences where provided. StoreStudyAsync constrains the study in the URI. Worklist update and typed state-change overloads accept the transaction UID that identifies workflow ownership. Cancellation overloads with a requester argument instead identify the requesting AE Title. The results table describes the payload type; always inspect Response.StatusCode, headers, and the operation-specific value for partial or pending outcomes.
Aspose.Medical.Dicom.Web.DicomWebClientResult<Aspose.Medical.Dicom.Web.Transactions.RetrieveInstanceResult> instance =
await client.Studies.RetrieveInstanceAsync("1.2.3", "1.2.3.4", "1.2.3.4.5");
Aspose.Medical.Dicom.DicomFile file = instance.Value.File;
Aspose.Medical.Dicom.Web.DicomWebClientResult<Aspose.Medical.Dicom.Web.Transactions.StoreInstancesResult> stored =
await client.Studies.StoreAsync(file);
Aspose.Medical.Dicom.Dataset storeReport = stored.Value.Response;
For large study retrieval, use the one-pass stream instead of accumulating all files:
await using Aspose.Medical.Dicom.Web.DicomWebClientStream<Aspose.Medical.Dicom.DicomFile> files =
await client.Studies.RetrieveStudyAsync("1.2.3");
await foreach (Aspose.Medical.Dicom.DicomFile item in files)
System.Console.WriteLine(item.Dataset.Count);
The other service groups use the same client and result conventions. These calls use UIDs from an existing deployment:
await using Aspose.Medical.Dicom.Web.DicomWebClientStream<Aspose.Medical.Dicom.Dataset> scheduled =
await client.ModalityWorklist.SearchAsync();
await foreach (Aspose.Medical.Dicom.Dataset step in scheduled)
System.Console.WriteLine(step.Count);
Aspose.Medical.Dicom.Web.DicomWebClientResult<Aspose.Medical.Dicom.Web.Transactions.CheckStorageCommitmentResult> commitment =
await client.StorageCommitment.CheckResultAsync("1.2.3.6");
if (commitment.Value.IsPending)
System.Console.WriteLine("Check again later");
Aspose.Medical.Dicom.Web.DicomWebClientResult<Aspose.Medical.Dicom.Web.Transactions.RetrieveModalityPerformedProcedureStepResult> mpps =
await client.ModalityPerformedProcedureSteps.RetrieveAsync("1.2.3.7");
Aspose.Medical.Dicom.Dataset procedureStep = mpps.Value.ProcedureStep;
Aspose.Medical.Dicom.Web.DicomWebClientResult<Aspose.Medical.Dicom.Web.Transactions.RetrieveNonPatientInstanceResult> palette =
await client.NonPatientInstances.RetrieveAsync("color-palettes", "1.2.3.8");
Aspose.Medical.Dicom.DicomFile paletteFile = palette.Value.File;
await using Aspose.Medical.Dicom.Web.DicomWebClientResponse rendered =
await client.Studies.RetrieveRenderedInstanceAsync("1.2.3", "1.2.3.4", "1.2.3.4.5");
rendered.EnsureSuccessStatusCode();
Read the raw rendered ContentReader or copy it to your output destination before disposing the response. The server must advertise and implement the requested representation. The client exposes MPR and 3D methods, but the bundled standard Studies handler currently throws NotSupportedException for those transactions; use a server with a custom implementation before calling them.
WADO-URI and separate service roots
Use ServiceBaseUris[DicomWebService.Uri] when WADO-URI has a different endpoint from the Studies service. The client adds requestType=WADO, the Study, Series, and SOP Instance UIDs, and contentType to the query. For rendered retrieval, provide a concrete non-DICOM contentType; do not use a wildcard. WADO-URI media types must not include transfer-syntax or charset parameters. This example retrieves both Part 10 and JPEG representations from an existing server:
using System.Net.Http.HttpClient transport = new();
Aspose.Medical.Dicom.Web.DicomWebClient client = new(transport,
new DicomWebClientOptions
{
BaseUri = new System.Uri("https://example.org/dicomweb/"),
ServiceBaseUris = System.Collections.Immutable.ImmutableDictionary<
Aspose.Medical.Dicom.Web.DicomWebService, System.Uri>.Empty.Add(
Aspose.Medical.Dicom.Web.DicomWebService.Uri,
new System.Uri("https://example.org/wado/"))
});
Aspose.Medical.Dicom.Web.DicomWebClientResult<
Aspose.Medical.Dicom.Web.Transactions.RetrieveUriDicomInstanceResult> instance =
await client.Uri.RetrieveDicomInstanceAsync("1.2.3", "1.2.3.4", "1.2.3.4.5");
System.Console.WriteLine(instance.Value.File.Dataset.Count);
await using Aspose.Medical.Dicom.Web.DicomWebClientResponse image =
await client.Uri.RetrieveRenderedInstanceAsync("1.2.3", "1.2.3.4", "1.2.3.4.5",
DicomWebMediaTypes.ImageJpeg,
new DicomWebRenderOptions { Quality = 80 });
image.EnsureSuccessStatusCode();
await using System.IO.FileStream output = File.Create("wado-instance.jpg");
await image.ContentReader.CopyToAsync(output);
Raw requests and response ownership
SendAsync(DicomWebClientRequest, token) sends a standard DicomWebTransaction with route-template values, ordered query parameters, headers, and optional DicomWebContent. It returns DicomWebClientResponse; dispose it after reading. StatusCode, IsSuccessStatusCode, Headers, ContentType, and ContentReader expose the live HTTP outcome. EnsureSuccessStatusCode throws HttpRequestException on unsuccessful HTTP status. ReadDatasetAsync, ReadDatasetsAsync, ReadDicomFileAsync, and ReadDicomFilesAsync parse one semantic form from the same forward-only body. Do not mix these readers with direct ContentReader reads on one response. Typed, materialized DicomWebClientResult<T> owns a consumed value and Response metadata; its response body has already been closed. Raw rendered and binary retrievals leave response consumption to you.
Aspose.Medical.Dicom.Web.DicomWebClientRequest request =
new(Aspose.Medical.Dicom.Web.Transactions.RetrieveCapabilities.Instance);
await using Aspose.Medical.Dicom.Web.DicomWebClientResponse response =
await client.SendAsync(request);
response.EnsureSuccessStatusCode();
System.Console.WriteLine(response.ContentType);
DicomWebClientRequest.RouteValues fills the named segments in a standard route template. This direct request asks for one study’s metadata, names its route value explicitly, and consumes the raw response as a dataset sequence:
using System.Net.Http.HttpClient transport = new();
Aspose.Medical.Dicom.Web.DicomWebClient client = new(transport,
new DicomWebClientOptions
{
BaseUri = new System.Uri("https://example.org/dicomweb/")
});
Aspose.Medical.Dicom.Web.DicomWebClientRequest request =
new(Aspose.Medical.Dicom.Web.Transactions.RetrieveStudyMetadata.Instance)
{
RouteValues = new System.Collections.Generic.Dictionary<string, string> { ["study"] = "1.2.3" },
Headers = new Aspose.Medical.Dicom.Web.DicomWebHeaders(
("Accept", [Aspose.Medical.Dicom.Web.DicomWebMediaTypes.ApplicationDicomJson]))
};
await using Aspose.Medical.Dicom.Web.DicomWebClientResponse response =
await client.SendAsync(request);
await foreach (Aspose.Medical.Dicom.Dataset metadata in response.ReadDatasetsAsync())
System.Console.WriteLine(metadata.Count);
See worklist and procedure step workflows, storage commitment and non-patient instances, and representations and streaming for service-specific requests and response consumption.
Failures and cancellation
Operations that return a materialized result or open a DicomWebClientStream<T> check the HTTP status before returning. On an unsuccessful HTTP status, they throw DicomWebClientException, which derives from HttpRequestException and exposes Response, a bounded ResponseBody, and IsResponseBodyComplete. The captured body can be incomplete if its limit is reached or reading fails; it is not necessarily a DICOM dataset. Transport failures and local input or payload validation can throw other exceptions.
Methods that return DicomWebClientResponse, including SendAsync and rendered or binary retrievals, leave HTTP status handling to the caller. Check IsSuccessStatusCode and read the raw body if you need error details, or call EnsureSuccessStatusCode to throw HttpRequestException. This raw path does not capture a DicomWebClientException.ResponseBody automatically. The semantic readers also require a successful status.
Cancellation must cover both opening a response and consuming its body:
| Operation | Cancellation scope |
|---|---|
| Materialized result | Its operation token covers sending the request and parsing the result. |
DicomWebClientStream<T> |
The operation token covers sending and opening the response. Pass an enumeration token through WithCancellation or GetAsyncEnumerator(token) to cancel subsequent item reads. |
Raw DicomWebClientResponse |
The operation token covers sending and acquiring the response. Pass a token to the semantic reader or ContentReader.CopyToAsync when consuming the body. |
| Notification connection | The connection token covers the opening handshake. Each ReceiveAsync accepts its own receive token. |
Dispose streamed and raw responses when reading ends or is canceled. A timeout for the whole download must remain active through body consumption; successfully opening a response does not mean that its payload has finished arriving.
Notifications
ConnectNotificationsAsync(requester, configure, token) on the client or Worklist opens the UPS WebSocket. Configure ClientWebSocketOptions when credentials or headers are needed. Dispose the connection after use. ReceiveAsync returns one parsed DICOM JSON event dataset or null after a close message; only one receive may be active. Binary, oversized, or malformed event messages fail. The server must have a subscription provider, an enabled notification route, and WebSocket hosting support.
State exposes the current System.Net.WebSockets.WebSocketState. Canceling a receive or failing to receive or parse an event aborts the connection. Dispose that connection and call ConnectNotificationsAsync again to resume receiving; another ReceiveAsync call on the aborted connection cannot resume the interrupted event. A normal close, indicated by null, also ends receiving on that connection.
await using Aspose.Medical.Dicom.Web.DicomWebNotificationConnection connection =
await client.ConnectNotificationsAsync("READER");
Aspose.Medical.Dicom.Dataset? eventReport = await connection.ReceiveAsync();
if (eventReport is not null)
System.Console.WriteLine(eventReport.Count);