Service registration¶
SAIF.NetCore.ServiceExtensions is the composition-root package for this mono-repo: the table below groups its registration surface into 19 catalog rows (23 individual method declarations total, once overload/wrapper pairs such as RegisterForWindowsService<T>/RegisterForWindowsService() are each counted) across IServiceCollection, IApplicationBuilder, IWebHostBuilder, and HostBuilder/IHostApplicationBuilder, plus 6 Startup base classes targeting four hosting contexts — external/internal web apps, Core (internal) APIs, Edge (external) APIs, and console/Windows-service hosts. A consuming application adds a single package reference, calls the relevant registration method(s) and/or inherits a Startup base class, and (for non-secure entry points) must be aware that several registrations are deferred failures rather than startup-time errors — see Required-but-not-registered services and Configuration.
Registration extension catalog¶
| Extension method | Hosting context | Parameters | Source |
|---|---|---|---|
RegisterEnvironmentClient(this IServiceCollection) |
Any | none | IServiceCollectionExtensions.cs |
RegisterSecureEnvironmentClient(this IServiceCollection, Type) |
Any | Type whose assembly becomes the system-hash identity |
IServiceCollectionExtensions.cs |
RegisterDBConnectionClient(this IServiceCollection) |
API / worker / console | none — requires a prior secure IEnvironmentClient registration to succeed at runtime |
IServiceCollectionExtensions.cs |
RegisterEdgeAPIAuthServices(this IServiceCollection) |
Edge API | none | IServiceCollectionExtensions.cs |
RegisterCoreAPIAuthServices(this IServiceCollection) |
Core API | none | IServiceCollectionExtensions.cs |
RequireAuthenticatedUser(this IServiceCollection) |
Web / API | none | IServiceCollectionExtensions.cs |
RegisterOidcServices(this IServiceCollection, AuthenticationChallengeType, bool useJwtRefreshMiddleware) |
External web | challenge type (Cookie/OpenIdConnect), JWT-refresh toggle | IServiceCollectionExtensions.cs |
AddWebAuthentication(this IServiceCollection, AuthenticationChallengeType) |
Web | challenge type | IServiceCollectionExtensions.cs |
RegisterForWindowsService<T>(this IServiceCollection, bool registerSecureEnvironmentClient = true) / RegisterForWindowsService(this IServiceCollection) |
Windows service / worker | T for hash identity; secure-client toggle (generic overload only) |
IServiceCollectionExtensions.cs |
RegisterLoggingService(this IServiceCollection) |
Any | none | IServiceCollectionExtensions.cs |
RegisterErrorHandlerService(this IServiceCollection) |
Any | none | IServiceCollectionExtensions.cs |
RegisterFactoryActivatedMiddleware(this IServiceCollection) |
Web / API | none — calls RegisterErrorHandlerService internally |
IServiceCollectionExtensions.cs |
AddErrorHandlerHook<T>(this IServiceCollection) |
Any | T : IErrorHandleable |
IServiceCollectionExtensions.cs |
ConfigureSaifLogger(this IApplicationBuilder) |
Web / API | none | IAppBuilderExtensions.cs |
ConfigureErrorHandling(this IApplicationBuilder) |
Web / API | none | IAppBuilderExtensions.cs |
ConfigureDebugRequestHandling(this IApplicationBuilder) |
Web / API | none | IAppBuilderExtensions.cs |
RegisterEnvironmentClient(this IWebHostBuilder) / RegisterSecureEnvironmentClient<T>(this IWebHostBuilder) |
Web (pre-Startup) |
T for hash identity (secure overload) |
IWebHostBuilderExtensions.cs |
BuildConsoleApp<TConsole>(this HostBuilder, string[] args) / BuildSaifConsoleApp<TConsole>(this HostBuilder, string[] args) |
Console | TConsole : IHostedService; args |
IHostBuilderExtensions.cs |
ConfigureOpenTelemetry(this IHostBuilder, Action<OpenTelemetryOptions>) / ConfigureOpenTelemetry(this IHostApplicationBuilder, Action<OpenTelemetryOptions>) |
Any | options callback | OpenTelemetryExtensions.cs |
Service registration catalog¶
| Service type | Implementation | Lifetime | Registered by | Condition | Source |
|---|---|---|---|---|---|
IHttpContextAccessor |
HttpContextAccessor |
Singleton | RegisterEnvironmentClient, RegisterSecureEnvironmentClient, AppStartup |
Always | IServiceCollectionExtensions.cs |
ISystemWrapper |
SystemWrapper (EnvironmentClient) |
Singleton | Both env-client methods | Always | IServiceCollectionExtensions.cs |
IHostResolver |
HostResolver (EnvironmentClient) |
Singleton | Both env-client methods | Always | IServiceCollectionExtensions.cs |
IHttpJsonClient |
HttpJsonClient (HttpClients) |
Transient | Both env-client methods | Always | IServiceCollectionExtensions.cs |
IEnvironmentClient |
BaseEnvironmentClient |
Singleton | RegisterEnvironmentClient |
Always | IServiceCollectionExtensions.cs |
IEnvironmentClient |
SecureEnvironmentClient |
Singleton | RegisterSecureEnvironmentClient |
Always | IServiceCollectionExtensions.cs |
ISystemHashService |
factory → null |
Singleton | RegisterEnvironmentClient |
Always (see Configuration dependencies) | IServiceCollectionExtensions.cs |
ISystemHashService |
factory → SystemHashService(Assembly) |
Singleton | RegisterSecureEnvironmentClient |
Always | IServiceCollectionExtensions.cs |
IDBConnectionClient |
factory → ConnectionClient |
Singleton | RegisterDBConnectionClient |
Always (credentials resolve correctly only against a secure client) | IServiceCollectionExtensions.cs |
IOptions<JwtBearerOptions> configurator |
ConfigureJwtBearerOptions |
Options | RegisterEdgeAPIAuthServices, RegisterCoreAPIAuthServices |
Always | IServiceCollectionExtensions.cs |
ISecurityClient |
SecurityClient |
Singleton (AuthService extensions) / Transient (AppStartup External branch) |
AddTokenIdentityService / AddIdentityAccessor / AppStartup.ConfigureServices |
Always where called; mixed lifetime is a known duplicate-registration finding — see Security and authorization | IServiceCollectionExtensions.cs, Startup/AppStartup.cs |
IIdentityService |
TokenIdentityService |
Scoped | AddTokenIdentityService (AuthService) |
Edge path | AuthService (pass-through) |
IIdentityServiceAccessor |
IdentityServiceAccessor |
Transient | AddTokenIdentityService (AuthService) |
Edge path | AuthService (pass-through) |
TokenIdentityService, WinIdentityService (self) |
— | Scoped | AddIdentityAccessor (AuthService) |
Core path | AuthService (pass-through) |
IIdentityServiceAccessor |
MultiIdentityServiceAccessor |
Transient | AddIdentityAccessor (AuthService) |
Core path | AuthService (pass-through) |
IAuthorizationPolicyProvider |
SecurityApiPolicy |
Transient | AddSecurityApiAuthorizeAttribute / AppStartup |
Core path / External web | AuthService (pass-through) |
IAuthorizationHandler |
SecurityApiHandler |
Singleton | Same as above | Core path / External web | AuthService (pass-through) |
JwtClaimMiddleware, LowerCaseUrlMiddleware, RefreshJwtMiddleware |
self | Scoped | RegisterOidcServices |
Always registered; wiring into the pipeline is conditional — see Middleware pipeline | OIDC (pass-through) |
IOidcSettings |
OidcSettings |
Singleton | RegisterOidcServices |
Always | OIDC (pass-through) |
IUrlCaseService |
UrlCaseService |
Scoped | RegisterOidcServices |
Always | OIDC (pass-through) |
RoleClaimTransformer (self) |
— | Scoped | RegisterOidcServices |
Always | OIDC (pass-through) |
IRoleClaimService |
RoleClaimService |
Scoped | RegisterOidcServices |
Always | OIDC (pass-through) |
IClaimTransformCacheService |
ClaimTransformationCacheService |
Singleton | RegisterOidcServices |
Always | OIDC (pass-through) |
ILoginRedirectService |
LoginRedirectService |
Transient | RegisterOidcServices |
Always | OIDC (pass-through) |
IJwtRefreshService |
JwtRefreshService |
Scoped | RegisterOidcServices |
useJwtRefreshMiddleware = true |
OIDC (pass-through) |
IJwtAuthorizationCookieClaimService |
JwtAuthorizationCookieClaimService |
Scoped | RegisterOidcServices |
Always | OIDC (pass-through) |
IDataProtectionCertService |
DataProtectionCertService |
Singleton | RegisterOidcServices |
Always | OIDC (pass-through) |
| Cookie / OIDC options configurators | ConfigureCookieAuthenticationOptions, ConfigureOpenIdConnectOptions |
Options | AddWebAuthentication |
Always | OIDC (pass-through) |
ISaifLogService |
SaifLog |
Singleton | RegisterLoggingService |
Always | Logging (pass-through) |
ISaifWindowsServiceLogService |
SaifWindowsServiceLog |
Singleton | RegisterForWindowsService |
Always | Logging (pass-through) |
IConsoleLogService |
ConsoleLogService |
Singleton | BuildSaifConsoleApp |
Always | Logging (pass-through) |
IWindowsServiceErrorHandler |
WindowsServiceErrorHandler |
Singleton | RegisterForWindowsService |
Always | ErrorHandler (pass-through) |
IErrorHandleable |
factory → ErrorHandler(null, env, log) |
Scoped | RegisterErrorHandlerService |
Always | ErrorHandler (pass-through) |
IErrorHandleable |
T (consumer hook) |
Scoped | AddErrorHandlerHook<T> |
Per call | consumer |
DynamicErrorHandler, DebugRequestHandler |
self | Transient | RegisterFactoryActivatedMiddleware |
Always | IServiceCollectionExtensions.cs |
AspNetSessionIdMiddleware, LegacyBolAuthMiddleware |
self | Scoped | AppStartup (flag-driven) |
EnableSessionMiddleware gates AspNetSessionIdMiddleware (registered and wired into the pipeline); EnableLegacyBolAuthMiddleware gates LegacyBolAuthMiddleware (registered only — never wired into the pipeline by this library) |
Startup/AppStartup.cs |
IHostedService |
TConsole |
Singleton | BuildConsoleApp |
Always | IHostBuilderExtensions.cs |
Lifetime totals by unique service→implementation pair (excluding IHttpContextAccessor, options configurators, and MS framework calls): Singleton 16, Scoped 15, Transient 7, plus ISecurityClient → SecurityClient registered with mixed lifetimes.
Options configuration¶
| Options type | Named instance | Configured by | Configuration keys / services read | Source |
|---|---|---|---|---|
JwtBearerOptions |
Bearer (JwtBearerDefaults.AuthenticationScheme) |
ConfigureJwtBearerOptions(IEnvironmentClient) |
AuthService Environment API keys — see Configuration | AuthService (pass-through) |
CookieAuthenticationOptions |
Cookies (CookieAuthenticationDefaults.AuthenticationScheme) |
ConfigureCookieAuthenticationOptions(IOidcSettings, ILoginRedirectService, IDataProtectionCertService, ISaifLogService) |
OIDC keys | OIDC (pass-through) |
OpenIdConnectOptions |
OpenIdConnect (OpenIdConnectDefaults.AuthenticationScheme) |
ConfigureOpenIdConnectOptions(IOidcSettings, ISaifLogService, ILoginRedirectService) |
OIDC keys | OIDC (pass-through) |
AuthenticationOptions |
inline lambda | AddWebAuthentication |
Default/challenge scheme names | IServiceCollectionExtensions.cs |
MvcOptions |
inline lambda (global AuthorizeFilter) |
RequireAuthenticatedUser |
none | IServiceCollectionExtensions.cs |
OpenTelemetryOptions |
code-only POCO | Action<OpenTelemetryOptions> callback passed to ConfigureOpenTelemetry |
Owner (default "Unknown"); not bound from IConfiguration |
OpenTelemetryOptions.cs |
Each IConfigureNamedOptions<T>.Configure(string name, T options) implementation above gates its configuration logic on an exact scheme-name match (if (name == <SchemeDefaults>.AuthenticationScheme)) and is a no-op for any other name, including the ASP.NET Core Options.DefaultName (unnamed) instance. This means registering one of these configurators has no effect unless the application also registers authentication under the matching named scheme — AddAuthentication().AddJwtBearer() (scheme Bearer), .AddCookie("Cookies"), and .AddOpenIdConnect() (default scheme name OpenIdConnect), all of which AddWebAuthentication/RegisterEdgeAPIAuthServices/RegisterCoreAPIAuthServices already do. A consumer who manually resolves/sets IOptions<JwtBearerOptions>.Value (the unnamed/default instance) is not configuring the instance the corresponding handler actually uses.
Startup base classes¶
| Base class | Inherits | Consumer type | Must implement | May override | Source |
|---|---|---|---|---|---|
AppStartup (abstract) |
— | External/internal web app | ConfigureUI(IApplicationBuilder app) (protected abstract) — the only abstract member; OidcMvcStartup/OidcRazorStartup implement it |
ConfigureServices, Configure, ConfigureAuthorization (all virtual with implemented defaults); AuthenticationChallengeType, EnableNewtonsoftJsonSerializer, UseJwtRefreshMiddleware, EnableSessionMiddleware, EnableLegacyBolAuthMiddleware are ordinary settable properties, not overridable |
Startup/AppStartup.cs |
OidcMvcStartup |
AppStartup |
External MVC web app | — | Implements ConfigureUI (default controller route); overrides ConfigureServices to add AddControllersWithViews() before calling base.ConfigureServices |
Startup/OidcMvcStartup.cs |
OidcRazorStartup |
AppStartup |
External Razor Pages web app | — | Implements ConfigureUI (Razor Pages endpoints); overrides ConfigureServices to add AddRazorPages() before calling base.ConfigureServices |
Startup/OidcRazorStartup.cs |
BaseApiStartup |
— | Any API | — (no abstract members) | ConfigureMiddleware, ConfigureMvcBuilder (both virtual with implemented defaults — consumers may override to add behavior, not to satisfy a required contract); EnableNewtonsoftJsonSerializer is an ordinary settable property |
Startup/BaseApiStartup.cs |
CoreAPIStartup |
BaseApiStartup |
Internal (Core) API | — | DisableAuthServices is a nonvirtual protected settable property (not overridable, but subclasses may set it); call EnableSecureEnvironmentClient<T>() to switch from the non-secure default to a secure client. Defines its own virtual ConfigureServices/Configure — BaseApiStartup has no Configure method of its own |
Startup/CoreAPIStartup.cs |
EdgeAPIStartup |
BaseApiStartup |
External (Edge) API | — | No secure-client switch exists; always non-secure, JWT-only auth | Startup/EdgeAPIStartup.cs |
Feature flags¶
| Name | Kind | Default | Effect | Source |
|---|---|---|---|---|
AuthenticationChallengeType |
Property | Cookie |
OpenIdConnect wires LowerCaseUrlMiddleware + the OIDC challenge (login app) |
Startup/AppStartup.cs |
UseJwtRefreshMiddleware / useJwtRefreshMiddleware |
Property / parameter | true |
Registers IJwtRefreshService and wires RefreshJwtMiddleware |
Startup/AppStartup.cs, IServiceCollectionExtensions.cs |
EnableSessionMiddleware |
Property | false |
Adds AddSession + wires AspNetSessionIdMiddleware into the pipeline |
Startup/AppStartup.cs |
EnableLegacyBolAuthMiddleware |
Property | false |
Registers LegacyBolAuthMiddleware only — it is never wired into the pipeline by this library |
Startup/AppStartup.cs |
EnableNewtonsoftJsonSerializer |
Property | false |
Swaps the JSON serializer; no configuration impact | Startup/AppStartup.cs, Startup/BaseApiStartup.cs |
DisableAuthServices (protected) |
Property | false |
true removes the AuthService registration (RegisterCoreAPIAuthServices) and skips UseAuthentication wiring on CoreAPIStartup — UseAuthorization is always called regardless of this flag |
Startup/CoreAPIStartup.cs |
EnableSecureEnvironmentClient<T>() |
Method call | Not called (non-secure + null hash) | Switches CoreAPIStartup to a secure client, enabling COREAPIENABLED-gated secure reads |
Startup/CoreAPIStartup.cs |
registerSecureEnvironmentClient |
Parameter | true |
RegisterForWindowsService<T>(false) falls back to the null-hash non-secure client |
IServiceCollectionExtensions.cs |
ASPNETCORE_HOST_LOCATION |
Environment variable (process, then machine) | HostLocation.NotDefined (behaves like INTERNAL) |
Selects OIDC vs. Core dual-auth stack — see Configuration | Startup/AppStartup.cs |
ASPNETCORE_REDIRECT_SSL |
Environment variable (machine only) | true |
Toggles UseHttpsRedirection() for AppStartup apps — see Configuration |
Startup/AppStartup.cs |
OpenTelemetryOptions.Owner |
Options property (code callback) | "Unknown" |
Emitted as the lower-cased OTel resource attribute owner |
OpenTelemetryOptions.cs |
Middleware pipeline¶
AppStartup.Configure¶
| Order | Middleware | Condition | Notes |
|---|---|---|---|
| 1 | Request-buffering lambda | Always | Enables request-body re-read for downstream handlers |
| 2 | AspNetSessionIdMiddleware |
EnableSessionMiddleware |
Fail-open: calls next() after issuing a redirect when the session cookie is absent — see BR-SE-16 |
| 3 | ConfigureErrorHandling → DynamicErrorHandler |
Always | Wraps all downstream middleware in exception handling |
| 4 | ConfigureDebugRequestHandling → DebugRequestHandler |
Always | Logs every request at Debug level |
| 5 | Authentication (UseAuthentication) |
Always | Scheme set depends on ASPNETCORE_HOST_LOCATION |
| 6 | LowerCaseUrlMiddleware |
External & AuthenticationChallengeType = OpenIdConnect |
OIDC pass-through middleware |
| 7 | JwtClaimMiddleware |
External | OIDC pass-through middleware |
| 8 | RefreshJwtMiddleware |
External & UseJwtRefreshMiddleware |
OIDC pass-through middleware |
| 9 | HSTS (UseHsts) |
Always | — |
| 10 | HTTPS redirect (UseHttpsRedirection) |
ASPNETCORE_REDIRECT_SSL ≠ false (machine scope) |
Web-app-only toggle |
| 11 | Static files (UseStaticFiles) |
Always | — |
| 12 | Routing (UseRouting) |
Always | — |
| 13 | Authorization (UseAuthorization) |
Always | — |
| 14 | MVC/Razor UI endpoints | Always | — |
| 15 | ConfigureSaifLogger |
Always | Resolves the configured logger and finishes its setup |
Note: LegacyBolAuthMiddleware is registered as a service by the EnableLegacyBolAuthMiddleware flag but is never added to this pipeline by any UseMiddleware call in this library.
CoreAPIStartup.Configure / EdgeAPIStartup.Configure¶
Each class defines its own Configure method (BaseApiStartup provides no Configure of its own). Both share the same shape, calling the inherited ConfigureMiddleware(app) first.
| Order | Middleware | Condition | Notes |
|---|---|---|---|
| 1 | ConfigureMiddleware(app) (inherited from BaseApiStartup) |
Always | virtual method with an implemented default (request buffering + ConfigureErrorHandling().ConfigureDebugRequestHandling()); consumers may override, calling base.ConfigureMiddleware(app) first to preserve ordering — it is not an abstract hook |
| 2 | Authentication (UseAuthentication) |
Always on Edge; Core unless DisableAuthServices |
— |
| 3 | HSTS (UseHsts) |
Always | — |
| 4 | HTTPS redirect (UseHttpsRedirection) |
Always | APIs always redirect, unlike web apps |
| 5 | Routing (UseRouting) |
Always | — |
| 6 | Authorization (UseAuthorization) |
Always, on both Edge and Core | Unlike authentication, DisableAuthServices does not gate this call — CoreAPIStartup.Configure calls app.UseAuthorization() unconditionally |
| 7 | Controller endpoints (incl. Pingable) | Always | WithPingableController() from ConfigureMvcBuilder |
| 8 | ConfigureSaifLogger |
Always | — |
Hosted services and health checks¶
| Type | Kind | Registered by | Behavior | Source |
|---|---|---|---|---|
TConsole |
IHostedService |
BuildConsoleApp<TConsole> |
Singleton; runs as the console application's entry hosted service | IHostBuilderExtensions.cs |
No AddHostedService calls and no health-check endpoints are registered by this library. Liveness is provided by WithPingableController() (PingableService package) in BaseApiStartup.ConfigureMvcBuilder for API startups only.
Required-but-not-registered services¶
| Service type | Consumer | Expected source |
|---|---|---|
ISaifLogService |
OidcSettings/pass-through OIDC services' logger dependencies |
Host application must also call RegisterLoggingService — RegisterOidcServices does not register it |
ISystemHashService (non-null) |
OidcSettings.AppCredentials getter (lazy, at property-access time — not at construction or IOidcSettings resolution) |
Only available when paired with RegisterSecureEnvironmentClient; pairing with the non-secure client leaves OidcSettings with the null placeholder, so only reading AppCredentials fails, not resolving IOidcSettings itself. DataProtectionCertService does not inject ISystemHashService at all — it reads IOidcSettings.DPCertName (an ordinary, non-secure setting) and calls IEnvironmentClient.IsDeveloperMachine() |
IEnvironmentClient, IHttpJsonClient, IHttpContextAccessor |
ConfigureJwtBearerOptions, SecurityClient, identity services |
Auth registration methods (RegisterEdgeAPIAuthServices/RegisterCoreAPIAuthServices) depend on an env-client registration having run first |
IEnvironmentClient (secure) |
RegisterDBConnectionClient factory |
Must be preceded by a secure env-client registration; otherwise credential resolution throws on first use |
IConfiguration, ILogger<T>, IHostEnvironment |
WindowsServiceErrorHandler, SaifWindowsServiceLog, SaifLog, ConsoleLogService, HostResolver |
Host-provided (Generic Host / ASP.NET Core framework) |
ISaifLogService |
ErrorHandler factory (RegisterErrorHandlerService) |
Must be registered by the caller (via RegisterLoggingService) before resolving the error handler |
Exactly one IErrorHandler |
DynamicErrorHandler |
Calling RegisterErrorHandlerService more than once causes .Single() to throw — see BR-SE-12 |
IAuthenticationService |
JwtAuthorizationCookieClaimService, RefreshJwtMiddleware |
Provided by AddAuthentication inside AddWebAuthentication — satisfied when that method is called |
Related documentation¶
- Index
- Overview
- Architecture
- Dependencies
- Configuration
- Operations and processes
- Business rules
- Security and authorization
- API reference
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.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/IServiceCollectionExtensions.cssrc/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/IAppBuilderExtensions.cssrc/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/IWebHostBuilderExtensions.cssrc/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/IHostBuilderExtensions.cssrc/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/OpenTelemetryExtensions.cs,OpenTelemetryOptions.cssrc/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/Startup/AppStartup.cs,OidcMvcStartup.cs,OidcRazorStartup.cs,BaseApiStartup.cs,CoreAPIStartup.cs,EdgeAPIStartup.cssrc/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/Middleware/AspNetSessionIdMiddleware.cs,LegacyBolAuthMiddleware.cs,DynamicErrorHandler.cs,DebugRequestHandler.cssrc/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtenstions.Tests/StartupTests.cs