SAIF.NetCore.HttpClients architecture¶
SAIF.NetCore.HttpClients is a thin, stateful facade over RestSharp 106 that implements the IHttpJsonClient/IHttpRequestResult contracts declared in SAIF.NetCore.ServiceContracts, giving every other SAIF.NetCore implementation library and consuming application a single reusable way to issue outbound JSON HTTP requests with bearer, basic, or NTLM authentication, retry-on-status-code behavior, and caller-identity header propagation.
Responsibilities¶
- Implement
IHttpJsonClientandIHttpRequestResult(HttpJsonClient,HttpRequestResult) so that callers program only against the ServiceContracts interfaces. - Hold per-instance request state: base URL,
ClientInfo(machine name, application ID, user name), timeout override,HttpClientOptions, bearer token, custom headers, NTLM authenticator, and the lastRequestResult. - Build and execute each RestSharp request, including identity headers (
Client-Name,Application-ID,Client-User), optional JSON body, and configured authentication. - Apply retry-on-status-code behavior for transient failures, sleeping between attempts on the calling thread.
- Normalize the RestSharp response into an
IHttpRequestResult, including status, content, headers, response date, and error-message extraction. - Offer result-conversion helpers (
HttpJsonClientExtensions,HttpRequestResult.GetResult<T>/GetContent<T>) so callers can deserialize responses without depending on RestSharp or Newtonsoft types directly.
Component boundaries¶
HttpJsonClient(implementsIHttpJsonClient): the request facade — construction, authentication setup, verb methods (Get/Post/Put/Patch/Deleteand their async equivalents), and the private request/execute/retry pipeline.HttpRequestResult(implementsIHttpRequestResult): the result model populated byHttpJsonClientafter each call.HttpJsonClientExtensions(static): content/header conversion helpers (ToReturnType<T>,GetHeaderValue<T>) and two unused helpers (CleanUrlPart,ToHttpContent).ClientInfo: the caller-identity value object (machine name, application ID, user name) propagated as request headers.ClientNotInitializedException: thrown when a verb method is called before bothClientInfoand the base URL are set.- Contract boundary:
IHttpJsonClient,IHttpRequestResult,HttpClientOptions, andHttpClientSerializerlive in SAIF.NetCore.ServiceContracts — this library supplies the implementation only.
Interaction model¶
- Every target URL is caller-supplied at request time; this library hard-codes no SAIF web API endpoint of its own, so it behaves purely as a generic HTTP transport used by other libraries and applications.
- Consumers resolve
IHttpJsonClientthrough dependency injection —SAIF.NetCore.ServiceExtensionsregisters it asTransient(services.AddTransient<IHttpJsonClient, HttpJsonClient>()) — then callSetClientInfo/SetOptions/authentication setters before issuing a request, because the DI container can only satisfy the parameterless constructor*. - The mutable
RequestResult/Headersinstance state makes a singleHttpJsonClientinstance unsafe to share across concurrent requests, consistent with theIHttpJsonClientXML doc's "intended to be used as a transient" guidance*. - A new
RestClientis created for every call and every retry attempt; retries block a thread-pool thread withThread.Sleeprather than an asynchronous delay. - No SAIF library-to-library delegation happens at runtime beyond the shared contract types — the request execution path is self-contained.
Architecture diagram¶
The following diagram shows the request pipeline from a verb-method call through RestSharp execution and retry to the returned result.
flowchart TD
A["Verb method<br>e.g. Get/PostAsync"] --> B[ValidateInitialization]
B -->|"clientInfo or baseUri null"| X[ClientNotInitializedException]
B --> C[ExecuteRestCall]
C --> D["CreateClient:<br>new RestClient, authenticator,<br>serializer, timeout"]
C --> E["CreateRequest:<br>body, identity headers,<br>bearer, custom headers"]
D --> F["client.Execute(request)"]
E --> F
F --> G{"Status in RetryOnStatusCodes<br>and retries remain?"}
G -->|yes| H["Thread.Sleep(RetryDelayInMs)"] --> C
G -->|no| I[CreateRequestResult]
I --> J["RequestResult field updated<br>and returned to caller"]
Sequence diagram¶
The following diagram shows a typical authenticated JSON request issued through the client.
sequenceDiagram
participant Consumer
participant HttpJsonClient
participant RestClient as "RestSharp RestClient"
participant Target as "Caller-supplied endpoint"
Consumer->>HttpJsonClient: SetClientInfo / SetOptions / BearerToken = token
Consumer->>HttpJsonClient: GetAsync(resource)
HttpJsonClient->>HttpJsonClient: ValidateInitialization
HttpJsonClient->>RestClient: CreateClient + CreateRequest
RestClient->>Target: HTTP request with identity + auth headers
Target-->>RestClient: HTTP response
RestClient-->>HttpJsonClient: IRestResponse
HttpJsonClient-->>Consumer: IHttpRequestResult
Design constraints¶
- No SAIF web API endpoint is hard-coded; every URL is supplied by the caller at request time, so this library cannot be documented against a fixed API surface.
- The generic
*Async<T>overloads are[Obsolete("This method not thread safe and has been depracated. Please use the overload <Verb>Async(string urlPart, object body).", true)]and cannot be called — only the non-generic async/sync verb methods and theHttpRequestResultconversion helpers are usable. - RestSharp 106.11.7 is several majors behind the current RestSharp release line, and this library has no DI/hosting surface of its own (no
IServiceCollectionextensions, middleware, or hosted services). - The library performs no configuration binding (
IConfiguration,IOptions<T>,IEnvironmentClient); all behavior-defining values — retry count, timeout ceiling, header names — are hard-coded constants or set programmatically throughHttpClientOptions/SetClientInfo.
Related documentation¶
- Index
- Overview
- Dependencies
- Operations and processes
- Business rules
- Security and authorization
- API reference
- SAIF.NetCore.ServiceContracts overview
Note: Statements marked with
*were inferred from code structure, naming conventions, or contextual evidence where direct confirmation was not available in source artifacts.
Sources¶
src/SAIF.NetCore.HttpClients/SAIF.NetCore.HttpClients/SAIF.NetCore.HttpClients/HttpJsonClient/HttpJsonClient.cssrc/SAIF.NetCore.HttpClients/SAIF.NetCore.HttpClients/SAIF.NetCore.HttpClients/HttpJsonClient/HttpJsonClientExtensions.cssrc/SAIF.NetCore.HttpClients/SAIF.NetCore.HttpClients/SAIF.NetCore.HttpClients/HttpJsonClient/HttpRequestResult.cssrc/SAIF.NetCore.HttpClients/SAIF.NetCore.HttpClients/SAIF.NetCore.HttpClients/ClientInfo.cssrc/SAIF.NetCore.HttpClients/SAIF.NetCore.HttpClients/SAIF.NetCore.HttpClients/Exceptions/ClientNotInitializedException.csArchitecture.md