This directory contains comprehensive real-world examples demonstrating how to use the Trellis library in production scenarios. Each example showcases Railway Oriented Programming (ROP), Domain-Driven Design (DDD), and functional programming patterns.
- Quick Start Guide - Learn Railway Oriented Programming fundamentals using standard functional programming terminology (
Bind,Map,Tap,Ensure,Combine,RecoverOnFailure,Match).
Complexity: ⭐⭐⭐⭐
A complete e-commerce system with order management, payment processing, and inventory control.
Key Features:
- Order aggregate with lifecycle management
- Payment processing with retry logic
- Inventory reservation and rollback
- Multi-step workflow orchestration
- Email notifications
- recovery patterns for failures
- Specification pattern for composable business rule filtering
Learn About:
- Complex domain aggregates
Bind,Ensure,Tap,RecoverOnFailurein practice- Async workflows with cancellation tokens
- Parallel validation
- Transaction-like behavior with rollback
Specification<T>withAnd,Or,Notcomposition
Files:
Aggregates/Order.cs- Order aggregate rootServices/PaymentService.cs- Payment processingServices/InventoryService.cs- Stock managementWorkflows/OrderWorkflow.cs- Complete order processing flowSpecifications/OrderSpecifications.cs- Business rule specifications
2. 🔐 Authorization
Complexity: ⭐⭐
Same authorization rules enforced two ways — with and without CQRS.
Key Features:
Actorwith permission-based and resource-based authorization- Direct service approach using
Trellis.Authorizationonly - Mediator pipeline approach using
Trellis.Mediator - Side-by-side comparison of identical outcomes
Learn About:
Actor,IActorProvider,IAuthorize,IAuthorizeResource<T>- Separating authorization from business logic
- When to use CQRS vs direct service calls
- Pipeline behaviors that enforce auth automatically
Files:
DirectServiceExample.cs- Manual authorization in service methodsMediatorExample.cs- Declarative authorization with pipeline behaviorsActors.cs- Test actors with varying permissionsDocument.cs- Simple document record and in-memory store
3. 🏦 Banking Transactions
Complexity: ⭐⭐⭐⭐⭐
A banking system with accounts, transfers, fraud detection, and security features.
Key Features:
- Account management (checking, savings, money market)
- Fraud detection and pattern analysis
- Daily withdrawal limits
- Overdraft protection
- Interest calculations
- Multi-factor authentication
- Account freeze/unfreeze
Learn About:
- Security and fraud prevention
- Complex validation chains
- Parallel fraud detection
- Recovery on security violations
- Audit trail with transaction history
- Status-based state machines
Files:
Aggregates/BankAccount.cs- Account aggregate with business rulesServices/FraudDetectionService.cs- Pattern-based fraud detectionWorkflows/BankingWorkflow.cs- Secure transaction processing
4. 👤 User Management
Complexity: ⭐⭐
User registration system with automatic value object validation and FluentValidation integration.
Key Features:
- User aggregate with 7 value objects (FirstName, LastName, EmailAddress, PhoneNumber, Age, CountryCode, Url)
- Automatic value object validation via
AddScalarValueValidation() - Password complexity requirements via FluentValidation
- Business rules (e.g., minimum age 18)
- Demonstrates both manual (
Result.Combine) and automatic validation
Learn About:
- Automatic value object validation in ASP.NET Core
- Mix of custom and built-in value objects
- Optional value object properties
- FluentValidation for complex business rules
- Type safety vs primitive obsession
Sample Endpoints:
// Manual validation using Result.Combine
POST /users/register
{
"firstName": "John",
"lastName": "Doe",
"email": "john@example.com",
"phone": "+14155551234",
"age": 25,
"country": "US",
"password": "SecurePass123!"
}
// Automatic validation - value objects validated during model binding
POST /users/registerWithAutoValidation
{
"firstName": "John",
"lastName": "Doe",
"email": "john@example.com",
"phone": "+14155551234",
"age": 25,
"country": "US",
"website": "https://johndoe.com",
"password": "SecurePass123!"
}Files:
SampleWeb/SampleUserLibrary/Aggregate/User.cs- User aggregate with 7 value objects and FluentValidationSampleWeb/SampleUserLibrary/Model/RegisterUserDto.cs- DTO with automatic value object validationSampleWeb/SampleUserLibrary/Model/RegisterUserRequest.cs- Request with raw strings (manual validation)SampleWeb/SampleUserLibrary/ValueObject/*.cs- Custom value objects (FirstName, LastName, UserId)
5. 🧪 Unit Test Examples
Complexity: ⭐⭐
Comprehensive test examples using xUnit.
Key Features:
- ValidationExample - Multi-field validation
- AsyncUsageExamples - Async ROP patterns
- MaybeExamples - Optional value handling
Learn About:
- Testing ROP workflows
- Async test patterns
- Maybe type usage
- Validation error testing
Files:
ValidationExample.cs- Combine and validation testingAsyncUsageExamples.cs- Async workflow testingMaybeExamples.cs- Optional value testing
6. 🌐 Web API Examples
Complexity: ⭐⭐⭐
ASP.NET Core MVC examples showing how to integrate ROP with web APIs.
Key Features:
- Controller actions returning Result
- Automatic error-to-HTTP status mapping
- Validation error responses
- Created/NotFound responses
Learn About:
ToActionResult()extension- BadRequest with validation details
- HTTP status code mapping
- API layer integration
Files:
Controllers/UsersController.cs- MVC controller with ROP
7. ⚡ Minimal API Examples
Complexity: ⭐⭐⭐
ASP.NET Core Minimal API examples with ROP integration and AOT support.
Key Features:
- Minimal API endpoints with Result
- User registration and retrieval
- Error demonstration endpoints (404, 409, 403, 401, 500)
- HTTP result mapping
- Source generation for AOT compatibility
- Welcome endpoint with API documentation
Learn About:
ToHttpResult()extension- Minimal API with functional patterns
- Route organization
- Results vs ActionResult
- AOT-compatible JSON serialization
Files:
API/UserRoutes.cs- User endpointsProgram.cs- Application setup with source generation
EmailAddress.TryCreate(email)
.Combine(FirstName.TryCreate(firstName))
.Combine(LastName.TryCreate(lastName))
.Bind((e, f, l) => User.Create(e, f, l))Used In: All examples Purpose: Validate multiple inputs independently and collect all errors
await GetCustomerAsync(id)
.ToResultAsync(Error.NotFound("Customer not found"))
.EnsureAsync(c => c.IsActive, Error.Validation("Inactive"))
.TapAsync(c => LogAccessAsync(c))
.BindAsync(c => ProcessAsync(c))Used In: EcommerceExample, BankingExample Purpose: Chain async operations with error handling
.RecoverOnFailure(
predicate: error => error is UnexpectedError,
func: () => RetryOperation()
)Used In: EcommerceExample (payment retry), BankingExample (account freeze) Purpose: Provide fallback behavior or cleanup on specific errors
var result = await Result.ParallelAsync(
() => GetStudentInfoAsync(studentId),
() => GetStudentGradesAsync(studentId),
() => GetLibraryBooksAsync(studentId)
)
.WhenAllAsync()
.BindAsync((info, grades, books) =>
PrepareReport(info, grades, books));Used In: EcommerceExample, BankingExample Purpose: Run multiple independent async operations concurrently for performance
public Result<Order> Submit()
{
return this.ToResult()
.Ensure(_ => Status == OrderStatus.Draft, Error.Validation("Cannot submit"))
.Ensure(_ => Lines.Count > 0, Error.Validation("Empty order"))
.Tap(_ => Status = OrderStatus.Pending)
.Map(_ => this);
}Used In: EcommerceExample (Order), BankingExample (BankAccount) Purpose: State machine with validation at each transition
- ⭐⭐ Beginner: Basic ROP concepts, simple validation
- ⭐⭐⭐ Intermediate: Value objects, aggregates, basic workflows
- ⭐⭐⭐⭐ Advanced: Async patterns, API integration, multiple services
- ⭐⭐⭐⭐⭐ Expert: Complex workflows, recovery, parallel operations
- ⭐⭐⭐⭐⭐⭐ Master: Security, fraud detection, advanced state management
Start with unit test examples to understand basic patterns:
- Read
ValidationExample.cs- LearnCombineandBind - Explore
MaybeExamples.cs- Understand optional values
Move to user management:
- Study
User.csaggregate - See how FluentValidation integrates
- Understand value objects
Learn web integration:
- Review
UsersController.csfor MVC pattern - Explore Minimal API examples
- Understand HTTP status mapping
Dive into e-commerce:
- Study
Order.csaggregate - Review
OrderWorkflow.csfor orchestration - Learn recovery patterns
Master banking example:
- Analyze
BankAccount.csstate machine - Study
FraudDetectionService.cs - Learn parallel validation
- Understand security patterns
Both E-commerce and Banking examples are standalone console applications:
Banking Example:
cd Examples/BankingExample
dotnet runE-commerce Example:
cd Examples/EcommerceExample
dotnet run- Right-click the example project (
BankingExampleorEcommerceExample) - Select "Set as Startup Project"
- Press F5 or click "Start Debugging"
- Watch the console output
All examples include test coverage. Run:
dotnet testStart the web applications:
cd Examples/SampleWebApplication/src
dotnet run
# Or for Minimal API
cd Examples/SampleMinimalApi
dotnet runModify the Program.cs in each example project:
Banking:
using BankingExample;
// Run all examples
await BankingExamples.RunExamplesAsync();
// Or run specific example
await BankingExamples.Example3_FraudDetection();E-commerce:
using EcommerceExample;
// Run all examples
await EcommerceExamples.RunExamplesAsync();
// Or run specific example
await EcommerceExamples.Example2_CompleteOrderWorkflow();Every example uses value objects to prevent primitive obsession:
OrderId,AccountId,CustomerId- Prevent ID confusionMoney- Prevent decimal arithmetic errorsEmailAddress,FirstName,LastName- Ensure valid data
No hidden exceptions or null checks:
- All failures return typed
Errorobjects - Errors aggregate when using
Combine - recovery handles specific error types
Build complex operations from simple parts:
- Each method does one thing
- Chain with
Bind,Ensure,Tap - Test components independently
All I/O is async with cancellation support:
BindAsync,EnsureAsync,TapAsync- Proper cancellation token propagation
- Parallel operations where beneficial
Domain rules are explicit and enforced:
- Status transitions validated
- Limits checked before operations
- Audit trails automatically maintained
Want to add a new example? Follow this structure:
- Check the main documentation
- Review examples article
- Open an issue on GitHub