Service registration¶
This library exposes three IServiceCollection extension methods (AddPingableTransient<TService, TImplementation>, AddPingableScoped<TService, TImplementation>, AddPingableSingleton<TService, TImplementation>) that dual-register an application's own pingable services, and one IMvcBuilder extension (WithPingableController()) that a host can call to enable the GET /Ping route and controller-based ping discovery in one step. WithPingableController() plus the host separately calling AddControllersAsServices() is the supported convenience path, not the only possible wiring: the /Ping route itself needs only PingableController's assembly present as an MVC application part and an IControllerRetriever registered (both of which WithPingableController() provides in one call, and which an equivalent explicit application-part registration plus a direct IControllerRetriever registration can also satisfy), and AddControllersAsServices() is only required when the host has pingable controllers it wants resolved through the controller-discovery channel — plain DI-registered IPingableService services never need it. SAIF.NetCore.ServiceExtensions's BaseApiStartup.ConfigureMvcBuilder makes both convenience calls automatically for any host that inherits it.
Registration extension catalog¶
| Extension method | Hosting context | Parameters | Source |
|---|---|---|---|
AddPingableTransient<TService, TImplementation>() |
API, worker, or console host (any IServiceCollection consumer) |
this IServiceCollection services; TService : class, IPingableService; TImplementation : class, TService, IPingableService |
src/SAIF.NetCore.PingableService/SAIF.NetCore.PingableService/Extensions/IServiceCollectionExtensions.cs |
AddPingableScoped<TService, TImplementation>() |
API, worker, or console host | this IServiceCollection services; same constraints as above |
src/SAIF.NetCore.PingableService/SAIF.NetCore.PingableService/Extensions/IServiceCollectionExtensions.cs |
AddPingableSingleton<TService, TImplementation>() |
API, worker, or console host | this IServiceCollection services; same constraints as above |
src/SAIF.NetCore.PingableService/SAIF.NetCore.PingableService/Extensions/IServiceCollectionExtensions.cs |
WithPingableController() |
API host (MVC) | this IMvcBuilder builder |
src/SAIF.NetCore.PingableService/SAIF.NetCore.PingableService/Extensions/MvcBuilderExtensions.cs |
Each AddPingable* method returns IServiceCollection (via its final .AddTransient/.AddScoped/.AddSingleton call) and WithPingableController() returns IMvcBuilder, so all four extensions are chainable with the rest of the host's DI/MVC setup.
Service registration catalog¶
| Service type | Implementation | Lifetime | Registered by | Condition | Source |
|---|---|---|---|---|---|
TService |
TImplementation |
Transient | AddPingableTransient<TService, TImplementation> |
Always (per call) | src/SAIF.NetCore.PingableService/SAIF.NetCore.PingableService/Extensions/IServiceCollectionExtensions.cs |
IPingableService |
factory: x => (TImplementation)x.GetRequiredService<TService>() |
Transient | AddPingableTransient<TService, TImplementation> |
Always (per call) | src/SAIF.NetCore.PingableService/SAIF.NetCore.PingableService/Extensions/IServiceCollectionExtensions.cs |
TService |
TImplementation |
Scoped | AddPingableScoped<TService, TImplementation> |
Always (per call) | src/SAIF.NetCore.PingableService/SAIF.NetCore.PingableService/Extensions/IServiceCollectionExtensions.cs |
IPingableService |
factory: x => (TImplementation)x.GetRequiredService<TService>() |
Scoped | AddPingableScoped<TService, TImplementation> |
Always (per call) | src/SAIF.NetCore.PingableService/SAIF.NetCore.PingableService/Extensions/IServiceCollectionExtensions.cs |
TService |
TImplementation |
Singleton | AddPingableSingleton<TService, TImplementation> |
Always (per call) | src/SAIF.NetCore.PingableService/SAIF.NetCore.PingableService/Extensions/IServiceCollectionExtensions.cs |
IPingableService |
factory: x => (TImplementation)x.GetRequiredService<TService>() |
Singleton | AddPingableSingleton<TService, TImplementation> |
Always (per call) | src/SAIF.NetCore.PingableService/SAIF.NetCore.PingableService/Extensions/IServiceCollectionExtensions.cs |
IControllerRetriever |
factory: x => new ControllerRetriever(names), where names is the list of ApplicationPartManager.ApplicationParts names snapshotted at the time WithPingableController() runs |
Singleton | WithPingableController() |
Always, once per call | src/SAIF.NetCore.PingableService/SAIF.NetCore.PingableService/Extensions/MvcBuilderExtensions.cs |
The IPingableService factory registration always resolves through the parallel TService registration and casts the result to TImplementation, so for Transient the two registrations yield independent instances per resolution, while for Scoped and Singleton the IPingableService entry shares the identical instance that TService resolves to within that scope or for the application's lifetime — there is no separate forwarding factory a host must supply (BR-15). WithPingableController() also adds this library's assembly as an MVC AssemblyPart (not a DI registration) so PingableController itself is discoverable by MVC's application-part system; see OP-04.
Host endpoint mapping¶
| Route | Verb | Controller / action | Authorization | Registered by | Source |
|---|---|---|---|---|---|
/Ping (optionally ?guid=<runId>) |
GET |
PingableController.Get |
[AllowAnonymous] (none) |
WithPingableController() (application part) + standard ASP.NET Core MVC routing |
src/SAIF.NetCore.PingableService/SAIF.NetCore.PingableService/Controllers/PingableController.cs |
WithPingableController() does not itself call MVC's route-mapping; it makes PingableController discoverable to MVC by adding its assembly as an AssemblyPart. Standard MVC attribute routing ([Route("Ping")], [HttpGet] on PingableController) then maps GET /Ping once the host's own MapControllers()/UseEndpoints() pipeline runs.
Options configuration¶
None. This library defines no IOptions<T>/IConfigureOptions<T> type and reads no configuration of its own.
Startup base classes¶
None directly in this library. However, SAIF.NetCore.ServiceExtensions's BaseApiStartup.ConfigureMvcBuilder calls builder.WithPingableController().AddControllersAsServices() for every host that inherits it, which satisfies both prerequisites below automatically (src/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/Startup/BaseApiStartup.cs).
Feature flags¶
None.
Middleware pipeline¶
None. This library adds no request-pipeline middleware; it only contributes an MVC application part and a controller.
Hosted services and health checks¶
None.
Controller-as-service prerequisite¶
ControllerRetriever.GetControllers resolves each discovered pingable-controller type from DI by concrete type (provider.GetService(type)), not through MVC's controller-activation path. This only succeeds, for a host that has pingable controllers to discover, if the host has separately called AddControllersAsServices() (or made an equivalent explicit DI registration for each pingable controller's concrete type) — WithPingableController() does not do this for the host, and does not call it for its own PingableController either. Without it, resolution returns null, and the subsequent call on that null result throws a NullReferenceException that surfaces as a 500 via the standard failure wrapping in OP-01 (BR-14). This prerequisite applies only to the controller-discovery channel; a host with no pingable controllers, or one that registers pingable services exclusively through AddPingable*/direct DI registration, is unaffected by it. BaseApiStartup.ConfigureMvcBuilder pairs the two convenience calls (WithPingableController().AddControllersAsServices()), so hosts built on it satisfy this prerequisite without extra code.
Required-but-not-registered services¶
| Service type | Consumer | Expected source |
|---|---|---|
ISaifLogService (optional) |
PingableController constructor (provider.GetService<ISaifLogService>()) |
Host application, if logging is desired; absence is tolerated — the controller falls back to a null logger (BR-12) |
AddControllersAsServices() registration behavior |
ControllerRetriever.GetControllers |
Host application's MVC builder configuration (see Controller-as-service prerequisite above) |
Related documentation¶
- Index
- Overview
- Architecture
- Dependencies
- Operations and processes
- Business rules
- Security and authorization
- API reference
Sources¶
src/SAIF.NetCore.PingableService/SAIF.NetCore.PingableService/Extensions/IServiceCollectionExtensions.cssrc/SAIF.NetCore.PingableService/SAIF.NetCore.PingableService/Extensions/MvcBuilderExtensions.cssrc/SAIF.NetCore.PingableService/SAIF.NetCore.PingableService/Controllers/PingableController.cssrc/SAIF.NetCore.PingableService/SAIF.NetCore.PingableService/Services/ControllerRetriever.cssrc/SAIF.NetCore.PingableService/SAIF.NetCore.PingableService/Services/IControllerRetriever.cssrc/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/Startup/BaseApiStartup.cs