WhizbangCoreOptions¶
Verified by tests
WhizbangCoreOptionsTests, TagOptionsTests, ServiceCollectionExtensionsTests — library CI run #37346231411 (2026-10-05)
WhizbangCoreOptions is the central configuration class for Whizbang. Pass a configuration lambda to AddWhizbang() to customize behavior.
Basic Usage¶
Basic Configuration
services.AddWhizbang(options => {
// Configure tag processing
options.Tags.UseHook<NotificationTagAttribute, MyNotificationHook>();
// Change processing mode
options.TagProcessingMode = TagProcessingMode.AsLifecycleStage;
// Disable tag processing entirely
options.EnableTagProcessing = false;
});
Properties¶
| Property | Type | Default | Purpose |
|---|---|---|---|
EnableTagProcessing |
bool |
true |
Master switch for message tag processing |
TagProcessingMode |
TagProcessingMode |
AfterReceptorCompletion |
When tag hooks run in the pipeline |
Tags |
TagOptions |
— | Tag hook registration (see below) |
Tracing |
TracingOptions |
— | Handler/message tracing configuration (see Tracing) |
Services |
ServiceRegistrationOptions |
— | Auto-registration behavior for discovered Lenses/Perspectives (see ServiceRegistrationOptions) |
AutoRegisterAspNetHosting |
bool |
true |
Automatically fold in AddWhizbangAspNet() when the Whizbang.Hosting.AspNet assembly is loaded; set false to call it yourself |
DefaultQueryScope |
QueryScope |
QueryScope.Tenant |
Default scope filtering for ILensQuery<TModel>.DefaultScope queries |
ShowBanner |
bool |
true |
Print the ASCII art banner on startup (the version log line always prints) |
ImmediateDetachedChainWarningThreshold |
int |
10 |
Warn when ImmediateDetached dispatch chains reach a multiple of this depth (no hard limit) |
EmptyStreamIdPolicy |
EmptyStreamIdPolicy |
Reject |
How rows with stream_id = Guid.Empty are handled (see Empty Stream ID Policy) |
EnableTagProcessing¶
| Property | Type | Default |
|---|---|---|
EnableTagProcessing |
bool |
true |
Controls whether message tag processing is enabled. Set to false to disable all tag hook invocations.
Disable Tag Processing
TagProcessingMode¶
| Property | Type | Default |
|---|---|---|
TagProcessingMode |
TagProcessingMode |
AfterReceptorCompletion |
Controls when tag hooks are executed in the message processing pipeline.
AfterReceptorCompletion (Default)¶
Tags are processed immediately after receptor completion, before lifecycle stages:
AsLifecycleStage¶
Tags are processed during lifecycle invocation. Use this when hooks depend on lifecycle receptors completing first:
Lifecycle Stage Mode
services.AddWhizbang(options => {
options.TagProcessingMode = TagProcessingMode.AsLifecycleStage;
});
Tags¶
| Property | Type |
|---|---|
Tags |
TagOptions |
Access to tag-specific configuration options. See TagOptions below.
TagOptions¶
TagOptions configures message tag hook registration and behavior.
| Property | Type | Default | Purpose |
|---|---|---|---|
HookRegistrations |
IReadOnlyList<TagHookRegistration> |
empty | The registered hook configurations |
PayloadSizeWarningThresholdBytes |
int? |
8192 |
Log a warning when a built tag payload exceeds this size (raw JSON text length); null disables |
PayloadSizeErrorThresholdBytes |
int? |
null |
Throw InvalidOperationException instead of dispatching when the payload exceeds this size (evaluated before hooks run); null disables |
UseHook<TAttribute, THook>¶
Register a hook for a specific tag attribute type:
Register Tag Hook
services.AddWhizbang(options => {
options.Tags.UseHook<SignalTagAttribute, SignalRNotificationHook<NotificationHub>>();
});
With Priority¶
Control execution order with priority (lower values execute first). The default priority is -100 (fires first):
Hook Priority
services.AddWhizbang(options => {
options.Tags.UseHook<SignalTagAttribute, ValidationHook>(priority: -100); // First (default)
options.Tags.UseHook<SignalTagAttribute, NotificationHook>(priority: 0); // After
options.Tags.UseHook<SignalTagAttribute, AuditHook>(priority: 500); // Last
});
With Lifecycle Stage¶
UseHook also accepts an optional fireAt parameter to restrict a hook to a specific LifecycleStage. When fireAt is null (the default), the hook fires at all stages:
Stage-Restricted Hook
services.AddWhizbang(options => {
options.Tags.UseHook<SignalTagAttribute, NotificationHook>(
fireAt: LifecycleStage.PostPerspectiveInline);
});
UseUniversalHook<THook>¶
Register a hook that fires for all tagged messages regardless of attribute type. The hook must implement IMessageTagHook<MessageTagAttribute>:
Universal Hook
services.AddWhizbang(options => {
// This hook fires for every tagged message
options.Tags.UseUniversalHook<LoggingHook>();
// With priority
options.Tags.UseUniversalHook<MetricsHook>(priority: 1000);
});
Complete Configuration Example¶
Complete Configuration
services.AddWhizbang(options => {
// Enable tag processing (default is true)
options.EnableTagProcessing = true;
// Process tags after receptor completion (default)
options.TagProcessingMode = TagProcessingMode.AfterReceptorCompletion;
// Register built-in tag hooks
// SignalRNotificationHook<THub> ships in Whizbang.SignalR;
// OpenTelemetrySpanHook / OpenTelemetryMetricHook ship in Whizbang.Observability
options.Tags.UseHook<SignalTagAttribute, SignalRNotificationHook<NotificationHub>>();
options.Tags.UseHook<TelemetryTagAttribute, OpenTelemetrySpanHook>();
options.Tags.UseHook<MetricTagAttribute, OpenTelemetryMetricHook>();
// Register custom tag hooks (user-defined MessageTagAttribute subclasses)
options.Tags.UseHook<AuditEventAttribute, AuditLogHook>();
options.Tags.UseHook<SlackNotificationAttribute, SlackHook>();
// Register hooks with priority (default is -100, lower fires first)
options.Tags.UseHook<SignalTagAttribute, ValidationHook>(priority: -100);
options.Tags.UseHook<SignalTagAttribute, EnrichmentHook>(priority: -50);
// Universal hook for logging all tagged messages
options.Tags.UseUniversalHook<TagLoggingHook>(priority: int.MaxValue);
// Payload size guards
options.Tags.PayloadSizeWarningThresholdBytes = 8192; // default
options.Tags.PayloadSizeErrorThresholdBytes = 65536; // default: null (disabled)
});
DI Registration¶
When you call AddWhizbang(options => ...):
- WhizbangCoreOptions is registered as Singleton (first call wins —
TryAddSingleton) - TagOptions is registered as Singleton
- All hooks are registered as Scoped (via
TryAddScoped) - IMessageTagProcessor is registered as Singleton with
IServiceScopeFactory - Generated service registration callbacks are invoked automatically — discovered Lenses and Perspectives are registered without an explicit
AddAllWhizbangServices()call (see ServiceRegistrationExtensions)
AddWhizbang() returns a WhizbangBuilder for chaining storage configuration (e.g., .WithEFCore<MyDbContext>().WithDriver.Postgres).
Multiple AddWhizbang Calls¶
AddWhizbang() can be called multiple times safely. The first call wins for option values; tag hook registrations from all calls are merged (duplicate attribute/hook pairs are skipped). This lets different parts of your startup code register hooks independently.
Hook Lifetime¶
Hooks are Scoped services, meaning:
- ✅ Hooks can inject scoped services (
DbContext,IHttpContextAccessor) - ✅ Multiple hooks in the same processing call share the same scope
- ✅ Each message dispatch gets a fresh scope
- ✅ Scope is disposed after processing completes
Hook with Scoped Dependencies
public class AuditHook : IMessageTagHook<AuditEventAttribute> {
private readonly MyDbContext _dbContext; // Scoped - works!
private readonly IHttpContextAccessor _httpContext; // Scoped - works!
public AuditHook(MyDbContext dbContext, IHttpContextAccessor httpContext) {
_dbContext = dbContext;
_httpContext = httpContext;
}
public async ValueTask<JsonElement?> OnTaggedMessageAsync(
TagContext<AuditEventAttribute> context,
CancellationToken ct) {
// Use scoped services safely
var userId = _httpContext.HttpContext?.User?.Identity?.Name;
_dbContext.AuditLogs.Add(new AuditLog { ... });
await _dbContext.SaveChangesAsync(ct);
return null;
}
}
Backward Compatibility¶
The parameterless AddWhizbang() overload still works:
Parameterless Overload
// This still works - uses default options
services.AddWhizbang();
// Equivalent to:
services.AddWhizbang(options => { });
See Also¶
- Message Tags - Complete tag processing guide
- Lifecycle Stages - Pipeline timing reference
- Dispatcher - Message dispatch and routing
ValidateRegistrations¶
bool, default true.
Validates at startup that every registered service can have its constructor satisfied, and throws naming both the missing service and the type that wanted it. The check reads service descriptors and resolves nothing, so it constructs no services and fires no factory side effects.
Set to false for a partial composition that deliberately registers only a subset, such as a test
fixture exercising one worker in isolation.