Introduction to Whizbang¶
Verified by tests
DispatcherTests, ReceptorTests, IPerspectiveForTests — library CI run #31657041675 (2026-08-13)
Whizbang is a comprehensive .NET library for building event-driven, CQRS, and event-sourced applications with zero reflection and native AOT compatibility from day one.
What is Whizbang?¶
Whizbang provides a complete foundation for building modern, scalable applications using message-driven architecture patterns. Unlike traditional frameworks that rely on runtime reflection, Whizbang uses source generators to discover and wire up your application components at compile time, resulting in:
- Blazing Performance: < 20ns in-process message dispatch with zero allocations
- AOT Ready: Full Native AOT support with no runtime surprises
- Type Safety: Compile-time verification of message handlers and routing
- Developer Experience: Rich IDE support with code navigation and discovery
Philosophy¶
Zero Reflection¶
Every feature in Whizbang is built without runtime reflection:
Zero Reflection
// Source generators discover this at compile time
public class CreateOrderReceptor : IReceptor<CreateOrder, OrderCreated> {
public async ValueTask<OrderCreated> HandleAsync(
CreateOrder message,
CancellationToken cancellationToken = default) {
// Business logic here
return new OrderCreated(OrderId: TrackedGuid.NewMedo(), /* ... */);
}
}
// Generated dispatcher code - no reflection!
// Routes messages at compile time with optimal performance
Benefits: - Native AOT deployment out of the box - Predictable performance (no reflection overhead) - Compile-time safety (broken handlers = compiler errors) - Faster startup times
Type-Safe Messaging¶
Whizbang enforces type safety at compile time:
Type-Safe Messaging
// Compiler knows CreateOrder → OrderCreated
var result = await dispatcher.LocalInvokeAsync<CreateOrder, OrderCreated>(command);
// Type mismatch? Compiler error!
// var wrong = await dispatcher.LocalInvokeAsync<CreateOrder, PaymentProcessed>(command); // ❌
Event-Driven Architecture¶
Built around three core patterns:
- Receptors: Stateless message handlers that make decisions
- Perspectives: Event listeners that maintain read models
- Lenses: Query interfaces for optimized data access
Event-Driven Architecture
// Receptor: Receives command, produces event
public class OrderReceptor : IReceptor<CreateOrder, OrderCreated> { }
// Perspective: Applies events to a read model (pure function)
public class OrderSummaryPerspective : IPerspectiveFor<OrderSummary, OrderCreated> { }
// Lens: Query interface for a read model (registered automatically per model)
public class OrderQueryService(ILensQuery<OrderSummary> lens) { }
Core Concepts (Quick Overview)¶
Dispatcher¶
Central message router with three dispatch patterns:
Dispatcher
// SendAsync: Command dispatch with delivery receipt (can work over wire)
var receipt = await dispatcher.SendAsync(new CreateOrder(/* ... */));
// LocalInvokeAsync: In-process RPC with typed result (< 20ns, zero allocation)
var result = await dispatcher.LocalInvokeAsync<CreateOrder, OrderCreated>(command);
// PublishAsync: Event broadcasting (fire-and-forget)
await dispatcher.PublishAsync(@event);
Receptors¶
Stateless message handlers:
Receptors
public class CreateOrderReceptor : IReceptor<CreateOrder, OrderCreated> {
public async ValueTask<OrderCreated> HandleAsync(
CreateOrder message,
CancellationToken cancellationToken = default) {
// Validate
if (message.Items.Count == 0) {
throw new InvalidOperationException("Order must have items");
}
// Make decision, return event
return new OrderCreated(
OrderId: TrackedGuid.NewMedo(),
CustomerId: message.CustomerId,
Items: message.Items,
Total: message.Items.Sum(i => i.Quantity * i.Price),
CreatedAt: DateTimeOffset.UtcNow
);
}
}
Perspectives¶
Event-driven read model updates via pure Apply functions — no I/O, no side effects; the framework handles persistence:
Perspectives
public sealed record OrderSummary {
[StreamId]
public Guid OrderId { get; init; }
public Guid CustomerId { get; init; }
public decimal Total { get; init; }
public string Status { get; init; } = "";
public DateTimeOffset CreatedAt { get; init; }
}
public class OrderSummaryPerspective : IPerspectiveFor<OrderSummary, OrderCreated> {
public OrderSummary Apply(OrderSummary currentData, OrderCreated eventData) =>
currentData with {
OrderId = eventData.OrderId,
CustomerId = eventData.CustomerId,
Total = eventData.Total,
Status = "Created",
CreatedAt = eventData.CreatedAt
};
}
Lenses¶
Query-optimized read access. ILensQuery<TModel> is registered automatically for every discovered perspective model:
Lenses
public class OrderQueryService(ILensQuery<OrderSummary> lens) {
public Task<OrderSummary?> GetOrderAsync(Guid orderId, CancellationToken ct = default) =>
lens.DefaultScope.GetByIdAsync(orderId, ct);
public async Task<List<OrderSummary>> GetRecentOrdersAsync(CancellationToken ct = default) {
return await lens.DefaultScope.Query
.OrderByDescending(row => row.UpdatedAt)
.Take(50)
.Select(row => row.Data)
.ToListAsync(ct);
}
}
Technology Stack (v1.0.0)¶
Whizbang is built on modern .NET:
| Technology | Version | Purpose |
|---|---|---|
| .NET | 10.0 | Target framework |
| Source Generators | Roslyn | Compile-time discovery |
[WhizbangId] generator |
Built-in | Strongly-typed UUIDv7 IDs |
| EF Core | 10.0 | Primary data driver (Postgres) |
| Dapper | Latest | Lightweight data access option |
| Azure Service Bus / RabbitMQ | Latest | Message transports |
| PostgreSQL | 16+ | Primary database |
| .NET Aspire | Latest | Orchestration & observability |
Project Structure (Library Projects)¶
whizbang/
├── src/
│ ├── Whizbang.Core/ # Core interfaces, dispatcher, workers, pooling
│ ├── Whizbang.Generators/ # Source generators (discovery)
│ ├── Whizbang.Data.EFCore.Postgres/ # EF Core + PostgreSQL driver
│ ├── Whizbang.Data.EFCore.Postgres.Generators/ # EF Core schema/registration generators
│ ├── Whizbang.Data.EFCore.Custom/ # EF Core attributes ([WhizbangDbContext])
│ ├── Whizbang.Data.Dapper.Postgres/ # Dapper + PostgreSQL
│ ├── Whizbang.Data.Dapper.Sqlite/ # Dapper + SQLite
│ ├── Whizbang.Data.Dapper.Custom/ # Dapper base classes
│ ├── Whizbang.Data.Postgres/ # PostgreSQL utilities + migrations
│ ├── Whizbang.Data.Schema/ # Schema definitions (wh_* tables)
│ ├── Whizbang.Transports.AzureServiceBus/ # Azure Service Bus transport
│ ├── Whizbang.Transports.RabbitMQ/ # RabbitMQ transport
│ ├── Whizbang.Transports.FastEndpoints/ # FastEndpoints integration
│ ├── Whizbang.Transports.HotChocolate/ # GraphQL integration
│ ├── Whizbang.Hosting.Azure.ServiceBus/ # Hosting extensions (ASB)
│ ├── Whizbang.Hosting.RabbitMQ/ # Hosting extensions (RabbitMQ)
│ ├── Whizbang.Sagas/ # Saga support
│ ├── Whizbang.SignalR/ # SignalR integration
│ ├── Whizbang.Observability/ # Observability extensions
│ └── Whizbang.Testing/ # Testing utilities
└── samples/
└── ECommerce/ # 12-project production sample
Key Features (v1.0.0)¶
Messaging Patterns¶
- ✅ Outbox Pattern: Reliable cross-service event publishing
- ✅ Inbox Pattern: Exactly-once message processing with deduplication
- ✅ Work Coordination: Atomic batch processing with lease-based distribution
- ✅ Message Envelopes: Hop-based observability for distributed tracing
Data Access¶
- ✅ Dapper Integration: Lightweight, high-performance SQL
- ✅ EF Core Integration: Full-featured ORM with code-first migrations
- ✅ Perspective Storage: Optimized read model management
- ✅ Event Store: Append-only event storage with PostgreSQL
Source Generators¶
- ✅ Receptor Discovery: Automatic handler registration
- ✅ Perspective Discovery: Event listener wiring
- ✅ Message Registry: VSCode extension integration
- ✅ Aggregate IDs: Strongly-typed identity generation
- ✅ JSON Contexts: AOT-compatible serialization
Infrastructure¶
- ✅ .NET Aspire: Automatic orchestration and service discovery
- ✅ Health Checks: Database and message transport readiness
- ✅ Object Pooling: Zero-allocation performance patterns
- ✅ Policy Engine: Decision trails and cross-cutting concerns
Transports¶
- ✅ Azure Service Bus: Production-ready message transport
- ✅ RabbitMQ: Production-ready message transport (local-dev friendly)
- ✅ In-Memory: Fast testing and development
Real-World Example: ECommerce Sample¶
Whizbang includes a complete 12-project production sample demonstrating:
- Backend for Frontend (BFF) with SignalR real-time updates
- Microservices (Order, Inventory, Payment, Shipping, Notification)
- Angular UI with NgRx state management
- Event-driven workflows with Outbox/Inbox patterns
- .NET Aspire orchestration for local development
- Integration testing with TUnit
Services:
- ECommerce.BFF.API - Backend for Frontend (perspectives + lenses + SignalR)
- ECommerce.OrderService.API - REST (FastEndpoints) + GraphQL order management
- ECommerce.InventoryWorker - Inventory reservation
- ECommerce.PaymentWorker - Payment processing
- ECommerce.ShippingWorker - Fulfillment coordination
- ECommerce.NotificationWorker - Cross-cutting notifications
- ECommerce.UI - Angular application
See ECommerce Tutorial for complete walkthrough.
When to Use Whizbang¶
Perfect For¶
✅ Event-Driven Applications: Microservices, event sourcing, CQRS ✅ High-Performance Systems: Need < 20ns in-process dispatch ✅ Native AOT Deployment: Cloud-native, serverless, edge computing ✅ Type-Safe Messaging: Compile-time verification required ✅ Complex Workflows: Order processing, sagas, distributed transactions ✅ Real-Time Systems: SignalR integration for live updates
Consider Alternatives If¶
❌ Simple CRUD: Whizbang is overkill for basic data entry apps ❌ No Messaging Needs: Traditional MVC/Razor Pages may be simpler ❌ Learning Curve: Team unfamiliar with event-driven patterns ❌ Rapid Prototyping: Source generators add compile-time overhead
Performance Characteristics¶
| Operation | Target | Description |
|---|---|---|
| LocalInvoke | < 20ns | In-process receptor invocation (zero allocation) |
| SendAsync | < 100μs | Outbox write + receipt generation |
| Perspective Update | < 50μs | Read model upsert |
| Lens Query | < 10μs | Indexed read model query |
| Source Generation | < 500ms | Full rebuild with all generators |
Learning Path¶
Beginner¶
- Installation - Set up your first project
- Quick Start - Hello World with Receptors + Dispatcher
- Project Structure - Organize your application
- Core Concepts: Receptors - Understand message handling
- Core Concepts: Dispatcher - Master message routing
Intermediate¶
- Perspectives - Build read models
- Lenses - Query optimization
- Outbox Pattern - Reliable messaging
- Inbox Pattern - Exactly-once processing
- ECommerce Sample - Production patterns
Advanced¶
- Source Generators - Understand code generation
- Extensibility - Custom implementations
- Performance Tuning - Optimize for scale
- Deployment - Production deployment
Next Steps¶
Ready to get started?
→ Installation Guide - Install Whizbang and create your first project
→ Quick Start Tutorial - Build a working app in 10 minutes
→ ECommerce Sample - Explore a production-ready example
Community & Support¶
- Documentation: https://whizbang-lib.github.io
- Source Code: https://github.com/whizbang-lib/whizbang
- Issues: https://github.com/whizbang-lib/whizbang/issues
- Samples: https://github.com/whizbang-lib/whizbang/tree/main/samples
Version 1.0.0 - Foundation Release | Last Updated: 2024-12-12