SAIF.Web.API architecture¶
SAIF.Web.API is a cross-cutting-concerns library for ASP.NET Web API 2 (System.Web.Http) host applications. It supplies a response/error post-processing message handler, a delegated role-based authorization attribute, an HTTPS-enforcement action filter, a static exception-to-HTTP-status mapper, and a request-header extension helper. It contains no controllers, no entry point, and no database access; every actual authorization and configuration decision is delegated to services assumed to be supplied by the hosting application — no such registration or supply exists inside this library.*
Responsibilities¶
- Post-process every outbound Web API response to add a correlation
MessageID/MessageIDUrl, redact sensitive request content from debug traces, and rewrite non-success responses into a structuredErrorResponsebody (ApiResponseHandler). - Enforce role/resource-based authorization on Web API controllers/actions by delegating the authorization decision to an injected
ISecurityApiClient(SaifAuthorizeAttribute). - Enforce HTTPS on Web API actions, with a configurable relaxation for local/developer requests (
RequireSSLAttribute). - Provide a static, reusable mapping from typed
SAIF.API.Exceptions.*exceptions toHttpStatusCodevalues for consuming controllers/exception filters (ExceptionHandler). - Consume a response-envelope/typed-exception contract (
ErrorResponse,SAIF.API.Exceptions.*) by fully-qualified type name; the compile-time-resolved assembly that actually supplies these types could not be confirmed — see Component boundaries.**
Component boundaries¶
ApiResponseHandler(SAIF.Web.API, derivesSystem.Net.Http.DelegatingHandler): registered by the host inHttpConfiguration.MessageHandlers; no such registration exists in this repository.* Once registered, it wraps every request/response pair, times it, resolvesILogService/IEnvironmentServiceper request viaIDependencyScope, and rewrites error responses.SaifAuthorizeAttribute(SAIF.Web.API, derivesSystem.Web.Http.AuthorizeAttribute, sealed): applied by the host to its own controllers/actions (no controllers exist inside this library, and no such application exists in this repository).* ResolvesISecurityApiClient/IEnvironmentServiceper request and never callsbase.IsAuthorized, so the base attribute's built-in identity check is bypassed entirely.RequireSSLAttribute(SAIF.Web.API, derivesSystem.Web.Http.Filters.ActionFilterAttribute): applied by the host as an action filter; no such application exists in this repository.* Reads the ambient application'sRequireSSLForLocalapp setting directly viaConfigurationManager.AppSettings, bypassingIEnvironmentService; no such application or setting exists in this repository.*ExceptionHandler(SAIF.Web.API, static class): a stateless mapping utility with no call site inside this library; intended for host controllers/exception filters to call explicitly.HttpRequestExtensions(SAIF.Web.API, static extension class): a generic request-header reader (TryGetFirstHeader) with no security-specific role in this library.ErrorResponse/SAIF.API.Exceptions.*(consumed types, not defined in this library's boundary):ApiResponseHandlerandExceptionHandlerreference these fully-qualified type names at compile time, butSAIF.Web.API.csprojdeclares no<ProjectReference>/<PackageReference>to any project or package that names them explicitly. A sibling project in this repository,SAIF.Web.API.Core(out of scope for this library's documentation), declares types with these exact namespace-qualified names, and theSAIF.Framework.CoreNuGet package is also a candidate supplier. Which assembly the compiler and runtime actually resolve these types from is unresolved — see Dependencies.**- Externally supplied contracts consumed via the host's dependency scope (not defined in this library):
IEnvironmentService,ILogService/ILogServiceForApi,ISecurityApiClient— all originate from theSAIF.Framework.CoreNuGet package.
Interaction model¶
- The hosting Web API application registers
ApiResponseHandlerinHttpConfiguration.MessageHandlers, so it wraps every inbound request/outbound response pair in the pipeline; no registration call site exists in this repository, so this describes the intended host-side usage pattern rather than an observed registration.* - The hosting application decorates its own controllers/actions with
[SaifAuthorizeAttribute(roles)]and/or[RequireSSLAttribute]; this library provides the attribute implementations only — it applies neither to any code of its own.* ApiResponseHandlerandSaifAuthorizeAttributeboth resolveILogService,IEnvironmentService, andISecurityApiClientper request via ASP.NET Web API'sIDependencyScope(request.GetDependencyScope().GetService(typeof(T))) — a service-locator pattern, not constructor injection. This means the library assumes the hosting application has registered these services with its ownIDependencyResolver; ifISecurityApiClientorIEnvironmentServiceis unregistered,SaifAuthorizeAttribute.IsAuthorizedthrowsMissingDependencyExceptionrather than denying access.*SaifAuthorizeAttributedelegates the actual per-role authorization decision toISecurityApiClient.IsAuthorized(user, role); the concrete implementation (WCFSecurityServicefacade, HTTP API, or other mechanism) is defined inSAIF.Framework.Coreand is not determinable from this repository.**SAIF.Web.APIreferencesErrorResponseandSAIF.API.Exceptions.*by fully-qualified type name at compile time, butSAIF.Web.API.csprojdeclares no<ProjectReference>or<PackageReference>that names either the siblingSAIF.Web.API.Coreproject or an equivalent package containing these types explicitly. BothSAIF.Web.API.Core(same repository) and theSAIF.Framework.CoreNuGet package are candidate suppliers of these identically-named types; which one the build actually resolves is an open question that would require inspecting the restoredSAIF.Framework.Core2.0.25119.2 assembly to settle — see Dependencies.**ExceptionHandler.ToHttpErrorhas no call site inside this library; it is exposed as a static utility for host controllers/exception filters to call explicitly.*
Architecture diagram¶
The following diagram shows the inbound request path through this library's components, from the client request to the response (or the unresolved contracts dependency).
flowchart TD
Client[Client request] --> Handler["ApiResponseHandler<br>(DelegatingHandler)"]
Handler --> Pipeline["Host Web API pipeline<br>(controllers/actions)"]
Pipeline --> AuthAttr["SaifAuthorizeAttribute<br>(AuthorizeAttribute)"]
Pipeline --> SSLAttr["RequireSSLAttribute<br>(ActionFilterAttribute)"]
Pipeline --> ExHandler["ExceptionHandler<br>(static utility,<br>host-invoked)"]
Handler -.->|"resolved assembly<br>unconfirmed"| Contracts["ErrorResponse /<br>SAIF.API.Exceptions.*<br>(source unresolved:<br>SAIF.Web.API.Core?<br>SAIF.Framework.Core?)"]
ExHandler -.->|"resolved assembly<br>unconfirmed"| Contracts
Handler --> ClientResp[Response to client]
The following diagram shows how ApiResponseHandler, SaifAuthorizeAttribute, and RequireSSLAttribute — the same nodes shown above — each depend on services the hosting application is expected to supply.
flowchart TD
AuthAttr["SaifAuthorizeAttribute<br>(AuthorizeAttribute)"] --> SecClient["ISecurityApiClient<br>(SAIF.Framework.Core)"]
Handler["ApiResponseHandler<br>(DelegatingHandler)"] --> EnvSvc["IEnvironmentService<br>(SAIF.Framework.Core)"]
AuthAttr --> EnvSvc
Handler --> LogSvc["ILogService /<br>ILogServiceForApi<br>(SAIF.Framework.Core)"]
AuthAttr --> LogSvc
SSLAttr["RequireSSLAttribute<br>(ActionFilterAttribute)"] --> AppConfig["Host<br>ConfigurationManager.<br>AppSettings"]
Sequence diagram¶
The following diagram shows the primary request sequence when a decorated action fails authorization.
sequenceDiagram
participant Client
participant Handler as ApiResponseHandler
participant Auth as SaifAuthorizeAttribute
participant SecClient as ISecurityApiClient
participant LogSvc as ILogService
Client->>Handler: HTTP request
Handler->>Auth: base.SendAsync -> pipeline dispatch
Auth->>Auth: Resolve ISecurityApiClient / IEnvironmentService via IDependencyScope
Auth->>SecClient: IsAuthorized(user, role) for each configured role
SecClient-->>Auth: false (no matching role)
Auth->>LogSvc: LogException(SecurityException) if user known
Auth-->>Handler: 401 Unauthorized response
Handler->>Handler: BuildApiResponse (MessageID, ErrorResponse body)
Handler-->>Client: 401 response with structured ErrorResponse
Design constraints¶
- Targets .NET Framework 4.6.2 and ASP.NET Web API 2 (
System.Web.Http, IIS/OWIN hosting) — not ASP.NET Core;RequireSSLAttribute's redirect further couples it toSystem.Web/HttpContext.Current. - All cross-cutting service dependencies (
IEnvironmentService,ILogService,ISecurityApiClient) are resolved via the per-requestIDependencyScopeservice locator, not constructor injection — the hosting application's DI container must register concrete implementations, or dependent operations fail (MissingDependencyExceptionfor authorization; graceful degradation for logging/Splunk-URL resolution).* - The library ships no
Web.config/app.config<appSettings>of its own; the one directly-read app setting (RequireSSLForLocal) is read from the ambient application's configuration — no such application or supplying configuration exists in this repository.* - No database access of any kind exists in this library — it is purely a Web API cross-cutting-concerns layer.
SAIF.Web.APIreferencesErrorResponse/SAIF.API.Exceptions.*by fully-qualified type name, butSAIF.Web.API.csprojexpresses no<ProjectReference>or<PackageReference>that names their supplying project/package explicitly; whether the compile-time assembly is the siblingSAIF.Web.API.Coreproject or theSAIF.Framework.Corepackage is unresolved — see Dependencies.**SaifAuthorizeAttributenever callsbase.IsAuthorized, so the baseAuthorizeAttribute's built-in authenticated-identity check is bypassed; an attribute applied with no roles authorizes every request, including unauthenticated ones.RequireSSLAttributeenforces HTTPS unconditionally for non-local requests; for local requests it is controlled by the ambient application'sRequireSSLForLocalapp setting — no such application or setting exists in this repository.* If the key is absent, or present but unparsable bybool.TryParse,requireSSLis set tofalseand local requests skip HTTPS enforcement — see Configuration.
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.
Related documentation¶
- Index
- Overview
- Dependencies
- Configuration
- Operations and processes
- Business rules
- Security and authorization
- API reference
Sources¶
src/SAIF.Web.API/ApiResponseHandler.cssrc/SAIF.Web.API/ExceptionHandler.cssrc/SAIF.Web.API/HttpRequestExtensions.cssrc/SAIF.Web.API/RequireSSLAttribute.cssrc/SAIF.Web.API/SaifAuthorizeAttribute.cssrc/SAIF.Web.API/app.configsrc/SAIF.Web.API/SAIF.Web.API.csprojsrc/SAIF.Web.API.Core/ApiResponse.cssrc/SAIF.Web.API.Core/BuildInfo.cssrc/SAIF.Web.API.Core/ErrorResponse.cssrc/SAIF.Web.API.Core/SAIFException.cssrc/SAIF.Web.API.Core/SAIF.Web.API.Core.csprojsrc/SAIF.Web.API.sln