ASP.NET Core Integration

ASP.NET Core integration

Reference the local Aspose.Medical.Dicom.Web.AspNetCore project or its matching package and the main Aspose.Medical assembly. The checked-out integration project targets .NET 10 and references Microsoft.AspNetCore.App. AddDicomWeb() registers a scoped hosting-neutral application and returns DicomWebAspNetCoreBuilder. Its overload accepts an Action<DicomWebAspNetCoreOptions>. ConfigureApplication(Action<DicomWebApplicationBuilder>) applies route and behavior changes whenever a scoped application is built.

Complete minimal application: standard handler

This Program.cs is a working read-only MWL-RS server with an intentionally empty in-memory worklist. It demonstrates the complete provider contract and responds to search requests without installing persistence:

Microsoft.AspNetCore.Builder.WebApplicationBuilder builder =
    WebApplication.CreateBuilder(args);
Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddScoped<
    Aspose.Medical.Dicom.Web.Providers.IDicomWebModalityWorklistProvider,
    EmptyModalityWorklist>(builder.Services);
Aspose.Medical.Dicom.Web.DicomWebServiceCollectionExtensions.AddDicomWeb(builder.Services)
    .AddStandardModalityWorklistService();

Microsoft.AspNetCore.Builder.WebApplication app = builder.Build();
Aspose.Medical.Dicom.Web.DicomWebEndpointRouteBuilderExtensions.MapDicomWeb(app, "/dicomweb");
await app.RunAsync();

public sealed class EmptyModalityWorklist : Aspose.Medical.Dicom.Web.Providers.IDicomWebModalityWorklistProvider
{
    public async System.Collections.Generic.IAsyncEnumerable<Aspose.Medical.Dicom.Dataset> FindCandidatesAsync(
        Aspose.Medical.Dicom.Web.Providers.DicomWebSearchContext search,
        [System.Runtime.CompilerServices.EnumeratorCancellation] System.Threading.CancellationToken cancellationToken = default)
    {
        cancellationToken.ThrowIfCancellationRequested();
        await System.Threading.Tasks.Task.CompletedTask;
        yield break;
    }
}

For a real worklist, query the backend in stable order from FindCandidatesAsync; the library performs final matching and projection. The equivalent hosting-neutral setup is DicomWebApplication.CreateBuilder().AddStandardModalityWorklistService(new EmptyModalityWorklist()).Build().

To expose Studies instead, use the complete InMemoryStudies and NoRenderedRepresentations classes in standard services and replace the worklist registrations above with:

Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton<
    Aspose.Medical.Dicom.Web.Providers.IDicomWebStudiesProvider,
    InMemoryStudies>(builder.Services);
Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton<
    Aspose.Medical.Dicom.Web.Providers.IDicomWebRepresentationProvider,
    NoRenderedRepresentations>(builder.Services);
Aspose.Medical.Dicom.Web.DicomWebServiceCollectionExtensions.AddDicomWeb(builder.Services)
    .AddStandardStudiesService();

The singleton in-memory archive survives request scopes for the lifetime of this demo process. Use application-managed persistence and an appropriate DI lifetime in a real service.

Complete custom handler for the same transaction

Replace the provider registration and standard registration above with this DI registration, and use EmptyWorklistHandler from custom handlers:

Aspose.Medical.Dicom.Web.DicomWebServiceCollectionExtensions.AddDicomWeb(builder.Services)
    .AddHandler<Aspose.Medical.Dicom.Web.Transactions.SearchModalityScheduledProcedureSteps,
                EmptyWorklistHandler>();

AddHandler<TTransaction,THandler> and AddHandlerFactory<TTransaction,TFactory> accept a ServiceLifetime (default Scoped); AddOpenRequestBehavior<TFactory> registers a Communication pipeline behavior factory. ConfigureApplication can additionally enable/disable services or add hosting-neutral behaviors. A scoped DicomWebApplication is built from registration callbacks using the request scope’s services. Use a handler factory when a new handler instance is required for each dispatch. A directly registered DI handler is resolved when its application scope is constructed. A later registration for the same transaction replaces the earlier one; register the standard service first when replacing only one of its transactions. Standard provider methods are also resolved from that scope.

Endpoint mapping and transport

MapDicomWeb(pattern) resolves the scoped application from request services. MapDicomWeb(pattern, application) uses the explicitly built immutable application. Both map the root and all resource paths beneath a static service-root path, such as /dicomweb, and return an IEndpointConventionBuilder so endpoint conventions can be applied to the group. The relative DICOMweb resource path excludes the service root. The base URI used for result links includes the request scheme, host, path base, and mapped root; configure ASP.NET Core forwarded headers in the host before relying on proxy-supplied origin values. The route group and host’s middleware supply ordinary ASP.NET Core endpoint features.

The adapter parses ordered query parameters and headers, wraps HttpRequest.BodyReader in a DicomWebPayloadReader, resolves an optional IAsyncBulkDataLoader from request services, passes RequestAborted to ProcessAsync, and writes status, response headers, Content-Type, optional Content-Length, and content to HttpResponse.BodyWriter. The adapter disposes its payload reader without completing the host-owned request pipe. A malformed query string receives HTTP 400. DicomWebResponse content writing may stream after handler completion, so scoped providers and request services must remain valid for the entire response. Exceptions not converted into an application response follow the host’s exception handling pipeline.

DicomWebAspNetCoreOptions.NotificationCloseTimeout defaults to 5 seconds and must be positive. It limits waiting for the peer to complete the WebSocket close handshake after server notification enumeration finishes. It does not configure ASP.NET Core request-body, WebSocket, authentication, or response timeouts.

Notification WebSockets and host policy

When UPS notifications are registered, call the host’s WebSocket middleware and map the DICOMweb endpoints in the usual ASP.NET Core pipeline. A DicomWebNotificationSession supplies handshake headers and ordered event-report datasets. The adapter accepts the WebSocket, writes each dataset as one DICOM JSON text message, and initiates a close handshake after the sequence ends. Request abortion cancels enumeration and transmission. The host must provide authenticated requester identity and appropriate authorization; it also owns CORS, TLS, forwarded headers, upload limits, and WebSocket policy. CORS does not restrict WebSocket origins; configure the host’s WebSocket origin policy separately. IDicomWebSubscriptionProvider owns subscription persistence and notification queues.

Place the middleware before the DICOMweb endpoint when using notification connections:

Microsoft.AspNetCore.Builder.WebSocketMiddlewareExtensions.UseWebSockets(app);
Aspose.Medical.Dicom.Web.DicomWebEndpointRouteBuilderExtensions.MapDicomWeb(app, "/dicomweb");

An explicitly built application can be mapped without AddDicomWeb:

Aspose.Medical.Dicom.Web.DicomWebApplication application =
    DicomWebApplication.CreateBuilder()
        .AddStandardModalityWorklistService(new EmptyModalityWorklist())
        .Build();
Aspose.Medical.Dicom.Web.DicomWebEndpointRouteBuilderExtensions.MapDicomWeb(app, "/dicomweb", application);

In that form the caller owns the application and its provider lifetimes. Use the DI form when request-scoped dependencies are required.