Skip to content

SAIF.Web.API.Clients business rules

This page captures business rules enforced by SAIF.Web.API.Clients. The library performs no database access, so no rule below carries a Tables or SQL field.

BR-CLI-001 NTLM default authentication

Field Value
Statement Requests are authenticated with Windows NTLM unless the caller supplies an alternative authenticator; a null authenticator is replaced with NTLM.
Trigger Client construction / every request execution.
Enforcement JsonHttpClient constructor (Uri, ClientInfo, IAuthenticator); JsonHttpClient.GetJsonResponse.
Outcome The RestClient always has a non-null authenticator; calls flow under the process's Windows identity by default.
Source src/SAIF.Web.API.Clients/JsonHttpClient.cs

BR-CLI-002 Caller identity headers required

Field Value
Statement Every outbound request must identify the calling machine, application, and user.
Trigger Every request.
Enforcement JsonHttpClient.GetJsonResponse adds Client-Name, Application-ID, Client-User headers from ClientInfo.
Outcome Headers are added from ClientInfo. A missing ClientInfo fails the request with NullReferenceException, because the value is not null-checked.
Source src/SAIF.Web.API.Clients/JsonHttpClient.cs

BR-CLI-003 On-behalf-of-user forwarding

Field Value
Statement When the target API must authorize on behalf of the end user rather than the service account, the current user's identity is forwarded.
Trigger JsonHttpClient.SetOnBehalfOfUserHeaders == true.
Enforcement JsonHttpClient.SetOnBehalfOfUserHeaders property; JsonHttpClient.GetJsonResponse.
Outcome Header OnBehalfOfUser is added. Requires an ambient ASP.NET HttpContext; a null context throws NullReferenceException.
Source src/SAIF.Web.API.Clients/JsonHttpClient.cs

BR-CLI-004 Forwarded user name normalization

Field Value
Statement A forwarded user name is normalized to its bare account name — the DOMAIN\ prefix and the @domain suffix are removed.
Trigger Building the OnBehalfOfUser header, or a direct call to HttpContextExtensions.DomainlessUser.
Enforcement HttpContextExtensions.DomainlessUser.
Outcome Downstream APIs receive an unqualified account name. Separators at index ≤ 1 are not stripped, and when both \ and @ are present the @ index is computed on the original string before the \ substring is taken, which can truncate the result incorrectly.
Source src/SAIF.Web.API.Clients/Extensions/HttpContextExtensions.cs

BR-CLI-005 Transient failure retry

Field Value
Statement Transient transport and gateway failures are retried up to 3 times with a fixed delay before being surfaced as errors.
Trigger Response status is in RetryOnStatusCodes (default 0, 401, 502, 503) and retry budget remains.
Enforcement JsonHttpClient.RetryOnStatusCodes, RetryDelayInMs, GetJsonResponse.
Outcome Up to 4 total attempts with a 1000 ms pause each; the final attempt's outcome is what the caller sees. A genuine 401 is retried 3 times before being reported.
Source src/SAIF.Web.API.Clients/JsonHttpClient.cs

BR-CLI-006 Non-success response failure conversion

Field Value
Statement Responses outside the 2xx–3xx range are treated as failures and converted to typed exceptions, unless the caller opts out.
Trigger JsonHttpClient.EnsureSuccessfulResponse == true (default) and status < 200 or >= 400.
Enforcement JsonHttpClient.EnsureSuccessfulResponse property; ExceptionHandler.EnsureSuccessfulResponse.
Outcome A SAIF.API.Exceptions.SAIFException subclass is thrown. With opt-out, the caller must inspect ApiResponse<T>.StatusCode. 3xx redirect statuses pass the guard and are treated as success.
Source src/SAIF.Web.API.Clients/JsonHttpClient.cs, src/SAIF.Web.API.Clients/ExceptionHandler.cs

BR-CLI-007 HTTP status to exception type mapping

Field Value
Statement HTTP failure statuses map to specific SAIF exception types: 404 → NoMatchingDataException, 401/403 → UnauthorizedAccessException, 400 → InvalidDataException, all others → InternalServerError.
Trigger A failed response reaching ExceptionHandler.ToKnownError.
Enforcement ExceptionHandler.ToKnownError (switch (status)).
Outcome The thrown exception carries the originating HttpStatusCode. The exception types themselves are defined in SAIF.Web.API.Core (SAIF.API.Exceptions.*, src/SAIF.Web.API.Core/SAIFException.cs).
Source src/SAIF.Web.API.Clients/ExceptionHandler.cs

BR-CLI-008 Exception message source preference

Field Value
Statement The exception message must prefer the API's own error text, drawn from the first matching of errormessage, exceptionmessage, message, usermessage; otherwise the raw payload is used.
Trigger Building a failure exception.
Enforcement ExceptionHandler.ToKnownError (token loop over the parsed response content).
Outcome A caller-meaningful message instead of a bare status code. Matching is on the top-level JSON token path only; multiple matches are concatenated as separate lines.
Source src/SAIF.Web.API.Clients/ExceptionHandler.cs

BR-CLI-009 Response success flag

Field Value
Statement A response is considered successful when its status code is below 400.
Trigger Building the transport response record.
Enforcement JsonHttpClient.GetJsonResponse (SuccessfulRequest = (int)response.StatusCode < 400).
Outcome The internal JsonResponse.SuccessfulRequest flag is set. This flag is not copied onto ApiResponse<T> and is therefore not observable by consumers.
Source src/SAIF.Web.API.Clients/JsonHttpClient.cs, src/SAIF.Web.API.Clients/JsonResponse.cs

BR-CLI-010 Per-client request timeout

Field Value
Statement A per-client request timeout applies only when explicitly configured to a positive value; otherwise the platform default governs.
Trigger Client construction with timeoutOverride; every request.
Enforcement JsonHttpClient.TimeoutOverride property; GetJsonResponse.
Outcome RestClient.Timeout is set only when TimeoutOverride > 0.
Source src/SAIF.Web.API.Clients/JsonHttpClient.cs

BR-CLI-011 Date time zone handling consistency

Field Value
Statement Date values on the wire are handled in the client's configured time-zone mode (default Local), consistently for both serialization and deserialization.
Trigger Every request and every response parse.
Enforcement JsonHttpClient.DateTimeZoneHandling property; JsonSerializer constructor; JsonHttpClient.GetContentArray<T>.
Outcome Request bodies and parsed responses agree on time-zone interpretation; DateParseHandling.DateTime forces DateTime (never DateTimeOffset).
Source src/SAIF.Web.API.Clients/JsonHttpClient.cs, src/SAIF.Web.API.Clients/JsonSerializer.cs

BR-CLI-012 Response payload shape normalization

Field Value
Statement A response payload is normalized into an array regardless of whether the API returned an array, a single object, or a scalar.
Trigger Any response deserialization.
Enforcement JsonHttpClient.GetContentArray<T>.
Outcome Consumers always receive T[] (or a single element via GetResult<T>), never a shape-dependent union.
Source src/SAIF.Web.API.Clients/JsonHttpClient.cs

BR-CLI-013 Single-value result coercion

Field Value
Statement Single-value results are coerced by target type: string is unquoted, primitives are converted directly, byte[] is base64-decoded, and the literal null yields the type default.
Trigger GetResult<T> on a completed GET.
Enforcement JsonHttpClient.GetResult<T>.
Outcome The caller receives a materialized T without writing conversion code. A malformed or quoted primitive payload throws FormatException/InvalidCastException uncaught to the caller.
Source src/SAIF.Web.API.Clients/JsonHttpClient.cs

BR-CLI-014 Responding server capture

Field Value
Statement The responding server instance is captured from the Server-Name response header and surfaced on the response envelope.
Trigger Envelope projection.
Enforcement JsonHttpClient.GetApiResponse<T>.
Outcome ApiResponse<T>.Server (from SAIF.Web.API.Core) carries the server name, or null when the header is absent. Header-name match is case-sensitive ordinal.
Source src/SAIF.Web.API.Clients/JsonHttpClient.cs

BR-CLI-015 JSON only content handling

Field Value
Statement Only application/json responses are handled; all default RestSharp content handlers are removed.
Trigger Every request.
Enforcement JsonHttpClient.GetJsonResponse (ClearHandlers() followed by AddHandler("application/json", () => new JsonDeserializer())).
Outcome XML and other content types are not auto-deserialized by RestSharp.
Source src/SAIF.Web.API.Clients/JsonHttpClient.cs

BR-CLI-016 Deserialization failure masking

Field Value
Statement A payload that fails to deserialize does not propagate the parse error: for a string target the exception message is returned as the value; for any other target an empty result is returned.
Trigger An exception inside GetContentArray<T>.
Enforcement JsonHttpClient.GetContentArray<T> (catch (Exception ex)).
Outcome No exception reaches the caller from the parse stage. This masks parse failures and can surface an exception message as business data — flagged as a defect risk.
Source src/SAIF.Web.API.Clients/JsonHttpClient.cs

BR-CLI-017 Failure message source selection

Field Value
Statement The failure message is chosen from the richest available source: response content first, then transport error information, then the status code and description.
Trigger Building a failure exception.
Enforcement ExceptionHandler.GetContent.
Outcome An error message is always produced (possibly empty). The transport-error branch has inverted conditional logic and yields a blank message when there is no response content*.
Source src/SAIF.Web.API.Clients/ExceptionHandler.cs

Notes

  • No input validation exists for methodUriSegment, serviceBaseUri, requestBody, or ClientInfo; there is no authorization decision logic, no rate limiting, circuit breaking, or caching, and no logging or auditing of any kind (verified absences).
  • EnvironmentSetting is a public key/value DTO with no consumer anywhere in this repository and enforces no business rule*.

Note: Statements marked with * were inferred from code structure, naming conventions, or contextual evidence where direct confirmation was not available in source artifacts. Statements marked with ** could not be confirmed; treat as unknown until verified.

Sources

  • src/SAIF.Web.API.Clients/JsonHttpClient.cs
  • src/SAIF.Web.API.Clients/ExceptionHandler.cs
  • src/SAIF.Web.API.Clients/JsonSerializer.cs
  • src/SAIF.Web.API.Clients/JsonResponse.cs
  • src/SAIF.Web.API.Clients/EnvironmentSetting.cs
  • src/SAIF.Web.API.Clients/Extensions/HttpContextExtensions.cs
  • src/SAIF.Web.API.Core/SAIFException.cs