Skip to content

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:

  1. Receptors: Stateless message handlers that make decisions
  2. Perspectives: Event listeners that maintain read models
  3. 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

  1. Installation - Set up your first project
  2. Quick Start - Hello World with Receptors + Dispatcher
  3. Project Structure - Organize your application
  4. Core Concepts: Receptors - Understand message handling
  5. Core Concepts: Dispatcher - Master message routing

Intermediate

  1. Perspectives - Build read models
  2. Lenses - Query optimization
  3. Outbox Pattern - Reliable messaging
  4. Inbox Pattern - Exactly-once processing
  5. ECommerce Sample - Production patterns

Advanced

  1. Source Generators - Understand code generation
  2. Extensibility - Custom implementations
  3. Performance Tuning - Optimize for scale
  4. 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