A simplified console application demonstrating all key features of Foundatio.Mediator with minimal boilerplate.
- Static handlers with minimal setup
- Convention-based discovery (classes ending in
Handler) - Simple
Handlemethods for messages
- OrderHandler with full CRUD operations
Result<T>pattern for success/failure handling- Validation with detailed error messages
- Status codes (Created, NotFound, NoContent, etc.)
- IAsyncEnumerable streaming via
CounterStreamHandler Invoke<IAsyncEnumerable<T>>for streaming results- Cancellation token support for early termination
- PublishAsync for events with multiple handlers
- Event-driven architecture examples
- Audit logging and notifications
- Automatic handler registration via source generator
- Logger injection and service resolution
- Clean service configuration
- ValidationMiddleware (static) - Using MiniValidation for automatic validation
- LoggingMiddleware (instance) - Performance tracking and execution logging
- Ordered execution with
[Middleware(Order = 10)]attributes
ConsoleSample/
├── Messages/
│ └── Messages.cs # All message types (commands, queries, events)
├── Handlers/
│ └── Handlers.cs # All handler implementations
├── Middleware/
│ ├── ValidationMiddleware.cs # Static validation middleware
│ └── LoggingMiddleware.cs # Instance logging middleware
├── Program.cs # Application entry point
├── SampleRunner.cs # Demo orchestration
└── ServiceConfiguration.cs # DI setup
public static class SimpleHandler
{
public static void Handle(Ping ping) { /* ... */ }
public static string Handle(GetGreeting greeting) { /* ... */ }
}public class OrderHandler
{
public async Task<Result<Order>> HandleAsync(CreateOrder command)
{
// Validation
if (string.IsNullOrWhiteSpace(command.CustomerId))
return Result<Order>.Invalid(ValidationError.Create("CustomerId", "Customer ID is required"));
// Business logic
var order = new Order(/* ... */);
// Event publishing
await _mediator.PublishAsync(new OrderCreated(/* ... */));
return Result<Order>.Created(order, $"/orders/{orderId}");
}
}public class OrderNotificationHandler
{
public void Handle(OrderCreated evt) { /* Send SMS */ }
public void Handle(OrderUpdated evt) { /* Send update */ }
}
public class OrderAuditHandler
{
public void Handle(OrderCreated evt) { /* Log creation */ }
public void Handle(OrderUpdated evt) { /* Log update */ }
public void Handle(OrderDeleted evt) { /* Log deletion */ }
}[Middleware(1)]
public static class ValidationMiddleware
{
public static HandlerResult Before(object message)
{
if (!MiniValidator.TryValidate(message, out var errors))
{
var validationErrors = errors.Select(kvp =>
ValidationError.Create(kvp.Key, string.Join(", ", kvp.Value)))
.ToArray();
return HandlerResult.ShortCircuit(Result.Invalid(validationErrors));
}
return HandlerResult.Continue();
}
}[Middleware(2)]
public class LoggingMiddleware
{
public Stopwatch Before(object message)
{
var stopwatch = Stopwatch.StartNew();
return stopwatch;
}
public void Finally(object message, Stopwatch stopwatch, Exception? exception)
{
stopwatch?.Stop();
if (exception != null)
_logger.LogError(exception, "❌ Failed {MessageType} after {ElapsedMs}ms",
message.GetType().Name, stopwatch?.ElapsedMilliseconds ?? 0);
else
_logger.LogDebug("🏁 Finished {MessageType} handler", message.GetType().Name);
}
}dotnet runThis will execute all examples showing:
- Simple ping/greeting operations
- Complete order CRUD lifecycle
- Counter streaming with cancellation
- Event publishing with multiple handlers
The sample uses Foundatio.Mediator's source generator to:
- Auto-discover handlers by convention
- Generate efficient wrapper code
- Validate call sites at compile time
- Register handlers with DI automatically
No interfaces or base classes required!