The dexpace .NET SDK is an HTTP-client toolkit, not an HTTP client. Dexpace.Sdk.Core
provides abstractions, models, and (over time) pipelines; consuming libraries plug in a concrete
transport via the IHttpClient / IAsyncHttpClient interfaces. This mirrors the dexpace/java-sdk
and dexpace/python-sdk ports, translated into .NET idioms.
| Concept | Java (Kotlin) | Python | .NET |
|---|---|---|---|
| Immutable model | data class + Builder |
@dataclass(frozen, slots) |
record / readonly record struct + with |
| SPI seam | fun interface |
typing.Protocol |
interface |
| Resource cleanup | AutoCloseable |
context manager (__enter__) |
IDisposable / IAsyncDisposable |
| Async contract | CompletableFuture |
async/await coroutine |
Task<T> |
| Body streaming | Okio Source/Sink |
iter_bytes / BinaryIO |
Stream + WriteToAsync/OpenReadAsync |
| Single source of truth for deps | libs.versions.toml |
pyproject.toml / uv.lock |
Directory.Packages.props |
The pluggable I/O seam that exists in the Java SDK (IoProvider over Okio) is not ported:
.NET's System.IO.Stream, Memory<byte>, and IAsyncDisposable cover the same surface natively,
exactly as the Python port leans on bytes / BinaryIO instead of an Okio analog.
- Bodies —
RequestBody/ResponseBodyare typed abstractions over outgoing and incoming payloads.RequestBody.WriteToAsync(Stream)is the primary streaming surface;ResponseBody.OpenReadAsync()/ReadAsBytesAsync()/ReadAsStringAsync()drain the response. Byte- and string-backed bodies are replayable; stream-backed bodies are single-use and throwStreamConsumedExceptionon a second pass. CallRequestBody.ToReplayableAsync()before the first send when retries are needed. - HTTP value models (
Http/Common) — immutableMethod,Protocol,MediaType,HttpHeaderName,Headers, plusStatusinHttp/Response.Headersis a case-insensitive multimap with non-destructiveWith/Set/Withoutand aBuilderfor batched edits. - Request / Response (
Http/Request,Http/Response) —Requestis an immutablerecord(method, absoluteUri,Headers, optionalRequestBody);Responseis a disposable carrier ofStatus,Headers,ResponseBody, and the negotiatedProtocol. - Transport SPI (
Client) —IAsyncHttpClient.ExecuteAsync(Request, CancellationToken)is the async-first seam;IHttpClient.Execute(Request)is the synchronous variant.HttpClientExtensionsbridges between them (AsAsync,AsBlocking).coreships no transport. - Errors (
Errors) —SdkExceptionroots a hierarchy distinguishing the three transport failure shapes (ServiceRequestException,ServiceResponseException,HttpResponseException) from body/stream lifecycle, serialization, and pipeline failures.
Dexpace.Sdk.Http.SystemNet adapts System.Net.Http.HttpClient to the SPI. It streams response
bodies (HttpCompletionOption.ResponseHeadersRead) rather than buffering, translates transport
faults into the SDK exception hierarchy, and is ownership-aware: a caller-supplied HttpClient is
never disposed by the adapter. Additional transports (e.g. a gRPC-web or socket-level transport)
would each adapt one library to the same interfaces.
Mirroring the Java/Python ports, the following land in later slices:
- Pipeline — staged policies (redirect, retry, idempotency, set-date, client-identity, logging, tracing) composed over the transport.
- Context chain — dispatch → request → exchange promotion carrying an instrumentation context.
- Auth — token credentials, bearer/basic policies, RFC 7235 challenge handling.
- SSE, pagination, webhooks, instrumentation — server-sent events, paged iteration, webhook signature verification, and tracing/metrics abstractions.