Skip to content

Architecture

PdfClient is a single, immutable-after-construction class that implements IPdfClient, wraps one SAIF.Web.API.Clients.JsonHttpClient field for its five remote members, and delegates its six local members to the static PdfAPI.Core.PdfClientService.

Architecture diagram

flowchart TD
    CONSUMER[Consuming application] --> IFACE["IPdfClient interface"]
    IFACE --> IMPL["PdfClient : IPdfClient"]
    IMPL --> INFO["ClientInfo<br/>caller-supplied, not populated by PdfClient"]
    IMPL --> HTTP["SAIF.Web.API.Clients.JsonHttpClient"]
    IMPL --> LOCAL["PdfAPI.Core.PdfClientService<br/>6 non-HTTP members"]
    HTTP --> URI["baseUri = url.TrimEnd('/') + '/v1/'"]
    URI --> API["PdfAPI REST API"]
    IMPL --> CONTRACTS["PdfAPI.Core contracts"]
    API --> CONTRACTS

Component responsibilities

Component Type Responsibility
IPdfClient Interface The public contract; declares 9 of the client's 11 public members
PdfClient Class Composes the relative URL per remote member, delegates to JsonHttpClient, and forwards local members to PdfClientService; also exposes IsPdfa and Track, which are on the concrete class only
JsonHttpClient SAIF.Web.API.Clients Serialization, transport, timeout, and the PostJson/GetResult result envelope
ClientInfo SAIF.Web.API.Clients Caller identity sent with each request; supplied by the caller, not built by PdfClient
PdfAPI.Core Contracts assembly Request and response DTOs shared with the API (ConvertRequest, MergeRequest, PdfResult, PdfTrackingInfo, PdfFormat, DocumentRange)
PdfClientService Local service (PdfAPI.Core.Services) Backs the six non-HTTP members: Version, Pages, IsPdf, HasFormFields, Flatten, Extract

Construction

PdfClient has exactly one public constructor and no separate initializer. There is no parameterless constructor and no two-phase initializer method — the client cannot be constructed in an uninitialized state, unlike a client with a separate initializer method taking a URL and timeout.

Constructor / initializer Parameters Effect
PdfClient(ClientInfo info, string url) info — caller-supplied identity; url — API base URL Builds baseUri from url and constructs the JsonHttpClient field, which is readonly
Parameterless constructor — Not present
Two-phase initializer method — Not present

Base URI composition

var baseUri = new Uri($"{url.TrimEnd('/')}/v1/");
_jsonHttpClient = new JsonHttpClient(baseUri, info);
Element Value Source
Base URL Caller-supplied url constructor argument PdfAPI.Client\PdfClient.cs:15
Version suffix v1/ Hard-coded in PdfClient.cs:17
Trailing-slash handling url.TrimEnd('/') applied before appending /v1/ PdfAPI.Client\PdfClient.cs:17

Both http://host/pdfapi and http://host/pdfapi/ compose the same base URI. There is no guard on url itself: a null value throws NullReferenceException from TrimEnd, and an empty/relative value throws UriFormatException from the Uri constructor.

ClientInfo population

Property Value Source
ApplicationId Not set by PdfClient Caller-supplied info argument, used as-is
MachineName Not set by PdfClient Caller-supplied info argument, used as-is
UserId Not set by PdfClient Caller-supplied info argument, used as-is

Every consumer observed in scope passes a default-constructed, empty ClientInfo (PdfApiClientTester\PdfApiClientTester\PdfTester.cs:23), so no application, machine, or user identity is populated by any caller in this repository.

Call pattern

Each remote member follows the same shape: compose a relative URL, call one JsonHttpClient method, and unwrap the result.

JsonHttpClient member Returns Used by this client for
GetResult<T>(url) T, returned directly with no unwrapping Track(long) only
GetResults<T>(url) T[] Not used by this client
PostJson<T>(url, body) Result envelope with .Results Convert (both overloads), Merge, IsPdfa — each unwraps with .Results.FirstOrDefault()

An empty .Results collection from PostJson<T> silently yields default(T) — false for IsPdfa, null for Convert/Merge — with no exception raised. See Tech debt.

Design constraints

  • No public constructor or member accepts a CancellationToken; every remote call is fully synchronous and blocks the calling thread for the HTTP round trip.
  • The single constructor makes _jsonHttpClient a readonly field assigned once, so an instance is immutable and has no shared mutable state after construction.
  • The vestigial private readonly string _pdfRootDirectory; field (PdfClient.cs:13) is declared but never assigned or read.

Inherited framework behavior

Serialization, request composition, timeout enforcement, and the PostJson/GetResult result envelope are implemented inside SAIF.Web.API.Clients.JsonHttpClient and are not re-documented here.

Sources

  • PdfAPI.Client\PdfClient.cs
  • PdfAPI.Client\IPdfClient.cs
  • PdfAPI.Core\Services\PdfClientService.cs