---
title: JsonHttpClient
summary: API reference for JsonHttpClient.
status: draft
owner: bendy
last_reviewed: 2026-09-15
library: SAIF.Web.API.Clients
reference_type: package
---

# JsonHttpClient

`JsonHttpClient` is the sole public entry point of `SAIF.Web.API.Clients`. It wraps a `RestSharp.RestClient` to issue authenticated, retried, header-annotated HTTP calls against a SAIF JSON Web API, and routes every public verb method through one shared private funnel (`GetJsonResponse`) so authentication, identity headers, retry, and success-enforcement apply uniformly and cannot be bypassed per call. It has no base class, defines no interface, and has no virtual members, so it cannot be substituted or mocked without wrapping it.

## Purpose
- Provide GET/POST/PUT/PATCH/DELETE verb methods (`GetResult<T>`, `GetResults<T>`, `GetResponse<T>`, `PostJson<T>`, `PutJson<T>`, `PatchJson<T>`, `DeleteJson<T>`) that a consuming application uses to call a SAIF Web API without hand-writing HTTP, authentication, retry, or JSON-shape-normalization code (see [Operations and processes](../../operations-processes.md)).
- Enforce [BR-CLI-001](../../business-rules.md#br-cli-001-ntlm-default-authentication), [BR-CLI-002](../../business-rules.md#br-cli-002-caller-identity-headers-required), [BR-CLI-005](../../business-rules.md#br-cli-005-transient-failure-retry), and [BR-CLI-006](../../business-rules.md#br-cli-006-non-success-response-failure-conversion) on every request via the shared `GetJsonResponse` funnel.
- Translate transport-level responses into the `ApiResponse<T>` envelope or a materialized `T`, normalizing array/object/scalar JSON shapes uniformly ([BR-CLI-012](../../business-rules.md#br-cli-012-response-payload-shape-normalization)).

## Context
- Namespace: `SAIF.Web.API.Clients`
- Assembly/package: `SAIF.Web.API.Clients` (NuGet package `SAIF.Web.API.Clients`)

## Public members
| Member | Signature | Purpose |
| --- | --- | --- |
| Constructor | `JsonHttpClient(Uri serviceBaseUri, ClientInfo clientInfo, IAuthenticator authenticator)` | Canonical constructor; falls back to `new NtlmAuthenticator()` when `authenticator` is `null` ([BR-CLI-001](../../business-rules.md#br-cli-001-ntlm-default-authentication)). |
| Constructor | `JsonHttpClient(Uri serviceBaseUri, ClientInfo clientInfo)` | Chains to the canonical constructor with `new NtlmAuthenticator()`. |
| Constructor | `JsonHttpClient(Uri serviceBaseUri, ClientInfo clientInfo, IAuthenticator authenticator, int timeoutOverride)` | Chains to the canonical constructor, then sets `TimeoutOverride`. |
| Constructor | `JsonHttpClient(Uri serviceBaseUri, ClientInfo clientInfo, int timeoutOverride)` | Chains to the canonical constructor with a fresh `NtlmAuthenticator`, then sets `TimeoutOverride`. This overload does not make a caller-supplied authenticator reachable, because it always passes a new `NtlmAuthenticator`*. |
| `TimeoutOverride` | `int { get; }` (ctor-assigned, default `0`) | Request timeout in milliseconds; applied only when greater than `0` ([BR-CLI-010](../../business-rules.md#br-cli-010-per-client-request-timeout)). |
| `DateTimeZoneHandling` | `Newtonsoft.Json.DateTimeZoneHandling { get; set; }` (default `Local`) | Governs both request serialization and response deserialization of date values ([BR-CLI-011](../../business-rules.md#br-cli-011-date-time-zone-handling-consistency)). |
| `EnsureSuccessfulResponse` | `bool { get; set; }` (default `true`) | When `true`, non-success responses are converted to typed exceptions instead of being returned to the caller ([BR-CLI-006](../../business-rules.md#br-cli-006-non-success-response-failure-conversion)). |
| `SetOnBehalfOfUserHeaders` | `bool { get; set; }` (default `false`) | When `true`, adds the `OnBehalfOfUser` header from the ambient `HttpContext`, requiring a web host ([BR-CLI-003](../../business-rules.md#br-cli-003-on-behalf-of-user-forwarding)). |
| `RetryDelayInMs` | `int { get; set; }` (default `1000`) | Sleep duration between retry attempts. |
| `RetryOnStatusCodes` | `IEnumerable<HttpStatusCode> { get; set; }` (default `{0, 502, 503, 401}`) | Status codes that trigger a retry before success is evaluated ([BR-CLI-005](../../business-rules.md#br-cli-005-transient-failure-retry)). |
| `GetResult<T>` | `T GetResult<T>(string methodUriSegment)` | Issues a GET and returns a single materialized `T` with type-specific coercion; see [GetResult\<T\>](../../operations/get-result.md). |
| `GetResults<T>` | `T[] GetResults<T>(string methodUriSegment)` | Issues a GET and returns `ApiResponse<T>.Results`; see [GetResults\<T\>](../../operations/get-results.md). |
| `GetResponse<T>` | `ApiResponse<T> GetResponse<T>(string methodUriSegment)` | Issues a GET and returns the full envelope; see [GetResponse\<T\>](../../operations/get-response.md). |
| `PostJson<T>` | `ApiResponse<T> PostJson<T>(string methodUriSegment, object requestBody)` | Issues a POST with a JSON body; see [write operations](../../operations/write-operations.md). |
| `PutJson<T>` | `ApiResponse<T> PutJson<T>(string methodUriSegment, object requestBody)` | Issues a PUT with a JSON body; see [write operations](../../operations/write-operations.md). |
| `PatchJson<T>` | `ApiResponse<T> PatchJson<T>(string methodUriSegment, object requestBody)` | Issues a PATCH with a JSON body; see [write operations](../../operations/write-operations.md). |
| `DeleteJson<T>` | `ApiResponse<T> DeleteJson<T>(string methodUriSegment, object requestBody)` | Issues a DELETE with a JSON body — there is no body-less DELETE overload; see [write operations](../../operations/write-operations.md). |

## Behavioral notes
- Every public verb method routes through the private `GetJsonResponse` funnel, so header injection, authentication, retry, and success-enforcement cannot be bypassed per call ([GetJsonResponse](../../operations/get-json-response.md)).
- All HTTP execution is synchronous and blocking (`client.Execute`, `Thread.Sleep` for retry delay); there is no `async`/`await` surface.
- A new `RestClient` is constructed for every call — there is no connection/handler reuse across calls*.
- `SetOnBehalfOfUserHeaders = true` couples the client to `System.Web.HttpContext.Current`; calling it from a non-web host (console/service/test) throws `NullReferenceException` because no guard exists.
- `GetContentArray<T>` (`internal static`) normalizes JSON response shapes for `GetResult<T>` and `GetResponse<T>`, but is not part of the public surface; see [GetContentArray\<T\>](../../operations/get-content-array.md).

## Constraints and usage notes
- `ClientInfo` passed to the constructor is not null-checked; a `null` value throws `NullReferenceException` when headers are added.
- `methodUriSegment`, `serviceBaseUri`, and `requestBody` receive no input validation from this library.

> **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.Web.API.Clients/JsonHttpClient.cs`
