$npx -y skills add wshaddix/dotnet-skills --skill csharp-wolverinefxBuild .NET applications with WolverineFX for messaging, HTTP services, and event sourcing. Use when implementing command handlers, message handlers, HTTP endpoints with WolverineFx.HTTP, transactional outbox patterns, event sourcing with Marten, CQRS architectures, cascading mess
| 1 | # WolverineFX for .NET |
| 2 | |
| 3 | ## When to Use This Skill |
| 4 | |
| 5 | Use this skill when: |
| 6 | - Building message handlers or command handlers with Wolverine |
| 7 | - Creating HTTP endpoints with WolverineFx.HTTP (alternative to Minimal API/MVC) |
| 8 | - Implementing event sourcing with Marten and Wolverine |
| 9 | - Setting up transactional outbox pattern for reliable messaging |
| 10 | - Configuring message transports (RabbitMQ, Azure Service Bus, Amazon SQS, TCP) |
| 11 | - Implementing CQRS with event sourcing |
| 12 | - Processing messages in batches |
| 13 | - Using cascading messages for testable, pure function handlers |
| 14 | - Configuring error handling and retry policies |
| 15 | - Pre-generating code for optimized cold starts |
| 16 | |
| 17 | ## Related Skills |
| 18 | |
| 19 | - **`efcore-patterns`** - Entity Framework Core patterns for data access |
| 20 | - **`csharp-coding-standards`** - Modern C# patterns (records, pattern matching) |
| 21 | - **`http-client-resilience`** - Polly resilience patterns (complementary) |
| 22 | - **`background-services`** - Hosted services and background job patterns |
| 23 | - **`aspire-configuration`** - .NET Aspire orchestration |
| 24 | |
| 25 | ## Core Principles |
| 26 | |
| 27 | 1. **Low Ceremony Code** - Pure functions, method injection, minimal boilerplate |
| 28 | 2. **Cascading Messages** - Return messages from handlers instead of injecting IMessageBus |
| 29 | 3. **Transactional Outbox** - Guaranteed message delivery with database transactions |
| 30 | 4. **Code Generation** - Runtime or pre-generated code for optimal performance |
| 31 | 5. **Vertical Slice Architecture** - Organize code by feature, not technical layers |
| 32 | 6. **Pure Functions for Business Logic** - Isolate infrastructure from business logic |
| 33 | |
| 34 | ## Required NuGet Packages |
| 35 | |
| 36 | ### Core Messaging |
| 37 | ```xml |
| 38 | <PackageReference Include="Wolverine" /> |
| 39 | <PackageReference Include="WolverineFx.Http" /> |
| 40 | ``` |
| 41 | |
| 42 | ### Persistence Integration |
| 43 | ```xml |
| 44 | <PackageReference Include="WolverineFx.Marten" /> |
| 45 | ``` |
| 46 | |
| 47 | ### Transports |
| 48 | ```xml |
| 49 | <PackageReference Include="WolverineFx.RabbitMQ" /> |
| 50 | <PackageReference Include="WolverineFx.AzureServiceBus" /> |
| 51 | <PackageReference Include="WolverineFx.Kafka" /> |
| 52 | <PackageReference Include="WolverineFx.AmazonSQS" /> |
| 53 | ``` |
| 54 | |
| 55 | ## Basic Setup |
| 56 | |
| 57 | ### Program.cs (ASP.NET Core) |
| 58 | |
| 59 | ```csharp |
| 60 | using JasperFx; |
| 61 | using Wolverine; |
| 62 | using Wolverine.Http; |
| 63 | |
| 64 | var builder = WebApplication.CreateBuilder(args); |
| 65 | |
| 66 | builder.Host.UseWolverine(opts => |
| 67 | { |
| 68 | opts.Policies.AutoApplyTransactions(); |
| 69 | opts.Policies.UseDurableLocalQueues(); |
| 70 | }); |
| 71 | |
| 72 | builder.Services.AddWolverineHttp(); |
| 73 | |
| 74 | var app = builder.Build(); |
| 75 | |
| 76 | app.MapWolverineEndpoints(); |
| 77 | |
| 78 | return await app.RunJasperFxCommands(args); |
| 79 | ``` |
| 80 | |
| 81 | ## Message Handlers |
| 82 | |
| 83 | ### Simple Message Handler |
| 84 | |
| 85 | ```csharp |
| 86 | public record DebitAccount(long AccountId, decimal Amount); |
| 87 | |
| 88 | public static class DebitAccountHandler |
| 89 | { |
| 90 | public static void Handle(DebitAccount command, IAccountRepository repository) |
| 91 | { |
| 92 | repository.Debit(command.AccountId, command.Amount); |
| 93 | } |
| 94 | } |
| 95 | ``` |
| 96 | |
| 97 | ### Handler with Cascading Messages |
| 98 | |
| 99 | ```csharp |
| 100 | public record CreateOrder(Guid OrderId, string[] Items); |
| 101 | public record OrderCreated(Guid OrderId); |
| 102 | |
| 103 | public static class CreateOrderHandler |
| 104 | { |
| 105 | public static (OrderCreated, ShipOrder) Handle( |
| 106 | CreateOrder command, |
| 107 | IDocumentSession session) |
| 108 | { |
| 109 | var order = new Order { Id = command.OrderId, Items = command.Items }; |
| 110 | session.Store(order); |
| 111 | |
| 112 | return ( |
| 113 | new OrderCreated(command.OrderId), |
| 114 | new ShipOrder(command.OrderId) |
| 115 | ); |
| 116 | } |
| 117 | } |
| 118 | ``` |
| 119 | |
| 120 | ### Using OutgoingMessages for Multiple Messages |
| 121 | |
| 122 | ```csharp |
| 123 | public static OutgoingMessages Handle(ProcessOrder command) |
| 124 | { |
| 125 | var messages = new OutgoingMessages |
| 126 | { |
| 127 | new OrderProcessed(command.OrderId), |
| 128 | new SendEmail(command.CustomerEmail, "Order processed"), |
| 129 | new UpdateInventory(command.Items) |
| 130 | }; |
| 131 | |
| 132 | messages.Delay(new CleanupOrder(command.OrderId), 5.Minutes()); |
| 133 | |
| 134 | return messages; |
| 135 | } |
| 136 | ``` |
| 137 | |
| 138 | ## HTTP Endpoints (WolverineFx.HTTP) |
| 139 | |
| 140 | ### Basic GET Endpoint |
| 141 | |
| 142 | ```csharp |
| 143 | [WolverineGet("/users/{id}")] |
| 144 | public static Task<User?> GetUser(int id, IQuerySession session) |
| 145 | => session.LoadAsync<User>(id); |
| 146 | ``` |
| 147 | |
| 148 | ### POST with Message Publishing |
| 149 | |
| 150 | ```csharp |
| 151 | [WolverinePost("/orders")] |
| 152 | public static async Task<IResult> CreateOrder( |
| 153 | CreateOrderRequest request, |
| 154 | IDocumentSession session, |
| 155 | IMessageBus bus) |
| 156 | { |
| 157 | var order = new Order { Id = Guid.NewGuid(), Items = request.Items }; |
| 158 | session.Store(order); |
| 159 | |
| 160 | await bus.PublishAsync(new OrderCreated(order.Id)); |
| 161 | |
| 162 | return Results.Created($"/orders/{order.Id}", order); |
| 163 | } |
| 164 | ``` |
| 165 | |
| 166 | ### Compound Handler (Load/Validate/Handle) |
| 167 | |
| 168 | ```csharp |
| 169 | public static class UpdateOrderEndpoint |
| 170 | { |
| 171 | public static async Task<(Order?, |