Skip to content

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

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.cs
  • src/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/IAppBuilderExtensions.cs
  • src/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/IWebHostBuilderExtensions.cs
  • src/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/IHostBuilderExtensions.cs
  • src/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/OpenTelemetryExtensions.cs, OpenTelemetryOptions.cs
  • src/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/Startup/AppStartup.cs, OidcMvcStartup.cs, OidcRazorStartup.cs, BaseApiStartup.cs, CoreAPIStartup.cs, EdgeAPIStartup.cs
  • src/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/Middleware/AspNetSessionIdMiddleware.cs, LegacyBolAuthMiddleware.cs, DynamicErrorHandler.cs, DebugRequestHandler.cs
  • src/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtenstions.Tests/StartupTests.cs