Skip to content

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)

Sources

  • src/SAIF.NetCore.PingableService/SAIF.NetCore.PingableService/Extensions/IServiceCollectionExtensions.cs
  • src/SAIF.NetCore.PingableService/SAIF.NetCore.PingableService/Extensions/MvcBuilderExtensions.cs
  • src/SAIF.NetCore.PingableService/SAIF.NetCore.PingableService/Controllers/PingableController.cs
  • src/SAIF.NetCore.PingableService/SAIF.NetCore.PingableService/Services/ControllerRetriever.cs
  • src/SAIF.NetCore.PingableService/SAIF.NetCore.PingableService/Services/IControllerRetriever.cs
  • src/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/Startup/BaseApiStartup.cs