Summary
Extend the AuthKit.Plugins.Abstractions plugin contract with explicit application lifecycle hooks and hosted service integration.
The goal is to allow plugins to safely initialize runtime resources, perform post start operations, and release resources during graceful shutdown while using the standard .NET hosting lifecycle.
The implementation must remain additive and preserve compatibility with existing plugins.
Goal
Provide first class plugin lifecycle support for:
- startup initialization,
- post start notification,
- graceful shutdown,
- and plugin provided
IHostedService instances.
Lifecycle operations must be deterministic, cancellation aware, and integrated with the normal ASP.NET Core/.NET host lifecycle.
Background
Plugins may need to allocate or initialize resources that cannot be handled during static service registration.
Examples include
External connections
Background workers
Caches
Runtime state
External registrations
Resource cleanup
Without explicit lifecycle hooks, plugins are forced to rely on application specific startup behavior or hosted service workarounds.
The plugin contract should expose explicit lifecycle points while avoiding the creation of custom lifecycle framework.
Scope
B6. Plugin Lifecycle Hooks
Add asynchronous lifecycle hooks:
Task OnStartingAsync(
CancellationToken cancellationToken);
Task OnStartedAsync(
CancellationToken cancellationToken);
Task OnStoppingAsync(
CancellationToken cancellationToken);
The exact naming may follow the existing AuthKit naming conventions, but the semantics must correspond to:
- Starting - before the application is considered started;
- Started - after successful host/application startup;
- Stopping - during graceful application shutdown.
If the existing specification requires the names OnStarting, OnStarted, and OnStopping, those names should be retained while using asynchronous return types.
B7. GetHostedServices
Add:
IReadOnlyList<IHostedService> GetHostedServices();
Plugins may return one or more hosted services that should participate in the standard .NET host lifecycle.
The AuthKit host is responsible for registering these services with DI.
Lifecycle Model
The expected lifecycle is:
Host Construction
│
▼
Plugin Configuration
│
▼
Host Build
│
▼
OnStarting
│
▼
Host Start
│
├── IHostedService.StartAsync
│
▼
Application Started
│
▼
OnStarted
│
▼
Running
│
▼
Shutdown Requested
│
▼
OnStopping
│
├── IHostedService.StopAsync
│
▼
Host Stopped
The exact relationship between plugin lifecycle hooks and the standard IHostedService lifecycle must be explicitly defined and tested by the host.
B6. OnStarting
OnStarting is intended for plugin initialization that must occur before the application is considered fully started.
Typical uses include:
Validate external resources
Initialize plugin runtime state
Warm required caches
Prepare connections
The method must support cancellation.
If cancellation is requested, the plugin must be allowed to stop its startup operation.
A plugin must not be expected to continue performing potentially blocking startup work after cancellation has been requested.
Startup Failure
If OnStarting fails for required plugin operation, the host must treat startup as failed.
The host must not silently continue as if the plugin initialized successfully.
The resulting exception must be observable through the normal host startup failure mechanism.
B6. OnStarted
OnStarted is called after the application has successfully started.
This hook is intended for operations that should only execute once the host is running.
Examples:
Start non critical synchronization
Notify external systems
Perform post-start registration
Initialize optional background state
OnStarted must not be invoked if application startup failed.
The host must ensure that the hook is invoked at most once per host lifecycle.
B6. OnStopping
OnStopping is called when the host begins graceful shutdown.
It is intended for plugin cleanup and shutdown preparation.
Examples:
Stop accepting plugin specific work
Flush buffered data
Release external registrations
Prepare resources for disposal
The cancellation token supplied to the hook must represent the host shutdown cancellation semantics.
The host must not indefinitely block shutdown because plugin ignores cancellation.
The exact shutdown timeout behavior should follow the standard .NET host configuration.
Cancellation
All asynchronous lifecycle hooks must support CancellationToken.
The host must pass the appropriate token from the application's lifecycle.
The host must not create unrelated cancellation tokens that disconnect plugin operations from the actual host lifecycle.
Tests must verify that cancellation is propagated.
Invocation Ordering
Lifecycle hook ordering must be deterministic.
For multiple plugins:
Plugin A OnStarting
Plugin B OnStarting
Plugin A OnStarted
Plugin B OnStarted
or another explicitly documented ordering is acceptable.
However, the host must not rely accidentally on:
- filesystem order,
- assembly load order,
- dictionary enumeration order,
- or undefined plugin discovery order.
The chosen ordering must be documented and tested.
The same principle applies to OnStopping.
Failure Isolation
Lifecycle failures must be handled explicitly.
If one plugin fails during startup:
Plugin A → success
Plugin B → failure
Plugin C → ...
the host must follow defined startup failure policy.
It must not silently mark Plugin B as healthy.
If cleanup is required for already started plugins, the host should follow the normal .NET graceful shutdown/failure semantics.
The exact failure policy must be documented by the implementation.
B7. Hosted Services
Plugins may return hosted services through:
IReadOnlyList<IHostedService> GetHostedServices();
The returned services must integrate with the standard .NET hosting infrastructure.
The host should register them through the existing DI container rather than manually invoking:
outside the normal host lifecycle.
Hosted Service Registration
For every plugin:
GetHostedServices()
↓
IHostedService instances
↓
DI registration
↓
.NET Host lifecycle
The host must ensure that returned services are registered before host startup.
Hosted services must participate in normal:
processing.
Hosted Service Lifetime
The implementation must define the expected lifetime of plugin provided hosted services.
Services should not be independently disposed by the plugin contract if they are registered with the application's DI container.
DI should remain responsible for their lifecycle.
The plugin should therefore not need to manually track and dispose services returned from GetHostedServices() unless the contract explicitly requires it.
Duplicate Hosted Services
The host must avoid accidental duplicate registration.
Calling plugin discovery/configuration more than once must not result in the same hosted service being registered multiple times.
If multiple distinct instances are intentionally returned by the plugin, the behavior must be documented.
Null and Invalid Results
GetHostedServices() must not return null.
If the plugin has no hosted services, it should return an empty collection:
Array.Empty<IHostedService>()
The host may defensively reject null result with an explicit contract/configuration error if the public API cannot guarantee non-nullability.
The host must not silently ignore invalid hosted service registrations.
Dependency Injection
Hosted services must use the existing AuthKit DI container.
Do not introduce:
- a second service provider,
- a custom service scope system,
- or a custom hosted service scheduler.
Dependencies required by plugin hosted services should be resolved through the application's normal DI infrastructure.
Compatibility
The implementation must be additive.
Existing plugins must continue to compile and load without modification.
Plugins that do not implement lifecycle hooks must remain valid.
Plugins that do not provide hosted services must remain valid.
Default interface implementations should be used where appropriate.
For example, optional lifecycle hooks may safely default to:
and the hosted service collection may default to:
Array.Empty<IHostedService>()
The exact compatibility mechanism must match the target framework and existing IAuthKitPlugin design.
Thread Safety and Reentrancy
The host must prevent duplicate lifecycle invocation.
A plugin must not receive:
for the same application lifecycle unless explicitly supported.
Similarly:
must not occur accidentally.
The host must also prevent OnStarted from being invoked after OnStopping has already begun.
Runtime State
Lifecycle hooks may maintain plugin runtime state.
However, the plugin contract must not require plugins to expose mutable lifecycle state publicly.
The host should treat lifecycle methods as lifecycle notifications rather than state-management APIs.
Logging and Diagnostics
Lifecycle failures should provide sufficient diagnostic information to identify:
- plugin name,
- lifecycle stage,
- underlying exception.
For example:
Plugin 'ExamplePlugin' failed during OnStarting.
The host should use its existing logging infrastructure.
Do not introduce separate plugin logging framework.
Testing Strategy
Tests should use sample plugin that records lifecycle events.
Example:
OnStarting
OnStarted
OnStopping
The test host should verify the exact order.
A second sample plugin should provide one or more hosted services and record:
HostedService.StartAsync
HostedService.StopAsync
The integration test should verify participation in the standard host lifecycle.
Validation
B6. Lifecycle Hooks
B7. Hosted Services
Compatibility
Documentation
Build and Tests
Acceptance Criteria
- Plugins can participate in host startup through
OnStarting.
- Plugins receive post start notification through
OnStarted.
- Plugins receive graceful shutdown notification through
OnStopping.
- All lifecycle hooks are asynchronous and cancellation aware.
- Lifecycle invocation order is deterministic.
- Lifecycle hooks cannot be accidentally invoked multiple times.
- Lifecycle failures are surfaced explicitly.
- Plugins can provide
IHostedService implementations.
- Plugin hosted services participate in the standard .NET host lifecycle.
- Hosted services use the existing DI infrastructure.
- No custom lifecycle or hosted service framework is introduced.
- Existing plugins remain fully backward compatible.
PluginContractValidator passes.
DevTokens continues to compile and load successfully.
Non Goals
This task does not include:
- endpoint mapping,
- middleware configuration,
- middleware pipeline positioning,
- plugin configuration binding,
- OpenAPI configuration,
- Marten configuration,
- authentication configuration,
- authorization configuration,
- redesigning
IAuthKitPlugin,
- or introducing custom application lifecycle framework.
These concerns belong to the other Section B issues.
Parent
Part of: Section B — Host Lifecycle and Hooks
Summary
Extend the
AuthKit.Plugins.Abstractionsplugin contract with explicit application lifecycle hooks and hosted service integration.The goal is to allow plugins to safely initialize runtime resources, perform post start operations, and release resources during graceful shutdown while using the standard .NET hosting lifecycle.
The implementation must remain additive and preserve compatibility with existing plugins.
Goal
Provide first class plugin lifecycle support for:
IHostedServiceinstances.Lifecycle operations must be deterministic, cancellation aware, and integrated with the normal ASP.NET Core/.NET host lifecycle.
Background
Plugins may need to allocate or initialize resources that cannot be handled during static service registration.
Examples include
Without explicit lifecycle hooks, plugins are forced to rely on application specific startup behavior or hosted service workarounds.
The plugin contract should expose explicit lifecycle points while avoiding the creation of custom lifecycle framework.
Scope
B6. Plugin Lifecycle Hooks
Add asynchronous lifecycle hooks:
The exact naming may follow the existing AuthKit naming conventions, but the semantics must correspond to:
If the existing specification requires the names
OnStarting,OnStarted, andOnStopping, those names should be retained while using asynchronous return types.B7.
GetHostedServicesAdd:
Plugins may return one or more hosted services that should participate in the standard .NET host lifecycle.
The AuthKit host is responsible for registering these services with DI.
Lifecycle Model
The expected lifecycle is:
The exact relationship between plugin lifecycle hooks and the standard
IHostedServicelifecycle must be explicitly defined and tested by the host.B6.
OnStartingOnStartingis intended for plugin initialization that must occur before the application is considered fully started.Typical uses include:
The method must support cancellation.
If cancellation is requested, the plugin must be allowed to stop its startup operation.
A plugin must not be expected to continue performing potentially blocking startup work after cancellation has been requested.
Startup Failure
If
OnStartingfails for required plugin operation, the host must treat startup as failed.The host must not silently continue as if the plugin initialized successfully.
The resulting exception must be observable through the normal host startup failure mechanism.
B6.
OnStartedOnStartedis called after the application has successfully started.This hook is intended for operations that should only execute once the host is running.
Examples:
OnStartedmust not be invoked if application startup failed.The host must ensure that the hook is invoked at most once per host lifecycle.
B6.
OnStoppingOnStoppingis called when the host begins graceful shutdown.It is intended for plugin cleanup and shutdown preparation.
Examples:
The cancellation token supplied to the hook must represent the host shutdown cancellation semantics.
The host must not indefinitely block shutdown because plugin ignores cancellation.
The exact shutdown timeout behavior should follow the standard .NET host configuration.
Cancellation
All asynchronous lifecycle hooks must support
CancellationToken.The host must pass the appropriate token from the application's lifecycle.
The host must not create unrelated cancellation tokens that disconnect plugin operations from the actual host lifecycle.
Tests must verify that cancellation is propagated.
Invocation Ordering
Lifecycle hook ordering must be deterministic.
For multiple plugins:
or another explicitly documented ordering is acceptable.
However, the host must not rely accidentally on:
The chosen ordering must be documented and tested.
The same principle applies to
OnStopping.Failure Isolation
Lifecycle failures must be handled explicitly.
If one plugin fails during startup:
the host must follow defined startup failure policy.
It must not silently mark Plugin B as healthy.
If cleanup is required for already started plugins, the host should follow the normal .NET graceful shutdown/failure semantics.
The exact failure policy must be documented by the implementation.
B7. Hosted Services
Plugins may return hosted services through:
The returned services must integrate with the standard .NET hosting infrastructure.
The host should register them through the existing DI container rather than manually invoking:
outside the normal host lifecycle.
Hosted Service Registration
For every plugin:
The host must ensure that returned services are registered before host startup.
Hosted services must participate in normal:
processing.
Hosted Service Lifetime
The implementation must define the expected lifetime of plugin provided hosted services.
Services should not be independently disposed by the plugin contract if they are registered with the application's DI container.
DI should remain responsible for their lifecycle.
The plugin should therefore not need to manually track and dispose services returned from
GetHostedServices()unless the contract explicitly requires it.Duplicate Hosted Services
The host must avoid accidental duplicate registration.
Calling plugin discovery/configuration more than once must not result in the same hosted service being registered multiple times.
If multiple distinct instances are intentionally returned by the plugin, the behavior must be documented.
Null and Invalid Results
GetHostedServices()must not returnnull.If the plugin has no hosted services, it should return an empty collection:
The host may defensively reject
nullresult with an explicit contract/configuration error if the public API cannot guarantee non-nullability.The host must not silently ignore invalid hosted service registrations.
Dependency Injection
Hosted services must use the existing AuthKit DI container.
Do not introduce:
Dependencies required by plugin hosted services should be resolved through the application's normal DI infrastructure.
Compatibility
The implementation must be additive.
Existing plugins must continue to compile and load without modification.
Plugins that do not implement lifecycle hooks must remain valid.
Plugins that do not provide hosted services must remain valid.
Default interface implementations should be used where appropriate.
For example, optional lifecycle hooks may safely default to:
and the hosted service collection may default to:
The exact compatibility mechanism must match the target framework and existing
IAuthKitPlugindesign.Thread Safety and Reentrancy
The host must prevent duplicate lifecycle invocation.
A plugin must not receive:
for the same application lifecycle unless explicitly supported.
Similarly:
must not occur accidentally.
The host must also prevent
OnStartedfrom being invoked afterOnStoppinghas already begun.Runtime State
Lifecycle hooks may maintain plugin runtime state.
However, the plugin contract must not require plugins to expose mutable lifecycle state publicly.
The host should treat lifecycle methods as lifecycle notifications rather than state-management APIs.
Logging and Diagnostics
Lifecycle failures should provide sufficient diagnostic information to identify:
For example:
The host should use its existing logging infrastructure.
Do not introduce separate plugin logging framework.
Testing Strategy
Tests should use sample plugin that records lifecycle events.
Example:
The test host should verify the exact order.
A second sample plugin should provide one or more hosted services and record:
The integration test should verify participation in the standard host lifecycle.
Validation
B6. Lifecycle Hooks
OnStartingexists.OnStartedexists.OnStoppingexists.CancellationToken.OnStartingexecutes at the defined startup stage.OnStartedexecutes only after successful application startup.OnStoppingexecutes during graceful shutdown.B7. Hosted Services
GetHostedServices()exists.IReadOnlyList<IHostedService>.Compatibility
DevTokenscontinues to compile and load successfully.PluginContractValidatorpasses.Documentation
Build and Tests
dotnet build AuthKit.Plugins.Abstractionssucceeds.Acceptance Criteria
OnStarting.OnStarted.OnStopping.IHostedServiceimplementations.PluginContractValidatorpasses.DevTokenscontinues to compile and load successfully.Non Goals
This task does not include:
IAuthKitPlugin,These concerns belong to the other Section B issues.
Parent
Part of: Section B — Host Lifecycle and Hooks