api-versioning
API versioning strategies for ASP.NET Core. Covers Asp.Versioning library, URL segment,…
Asynchronous messaging patterns for .NET applications. Covers Wolverine and MassTransit, outbox pattern, saga and choreography, and broker configuration for RabbitMQ and Azure Service Bus. Load this skill when implementing event-driven communication, background processing,
$ npx -y skills add codewithmukesh/dotnet-claude-kit --skill messaging --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/messagingContext preview
The summary Claude sees to decide when to auto-load this skill.
Asynchronous messaging patterns for .NET applications. Covers Wolverine and MassTransit, outbox pattern, saga and choreography, and broker configuration for RabbitMQ and Azure Service Bus. Load this skill when implementing event-driven communication, background processing,
name: messaging description: > Asynchronous messaging patterns for .NET applications. Covers Wolverine and MassTransit, outbox pattern, saga and choreography, and broker configuration for RabbitMQ and Azure Service Bus. Load this skill when implementing event-driven communication, background processing, module-to-module messaging, or when the user mentions "Wolverine", "MassTransit", "message bus", "RabbitMQ", "Azure Service Bus", "event", "publish", "consumer", "outbox", "saga", "integration event", "queue", or "pub/sub".
1. **Wolverine is the recommended default** — MIT licensed, combines mediator + messaging in one library with built-in outbox, saga support, and convention-based handlers. MassTransit is an alternative but requires a commercial license from v9. 2. **Outbox pattern for reliability** — Always use the transactional outbox to ensure messages are published only when the database transaction succeeds. 3. **Choreography for simple flows, saga for complex** — If a workflow has 2-3 steps, use event choreography. If it has compensating actions or complex state, use a saga. 4. **Messages are contracts** — Put message types in a shared contracts project. Keep them as simple records with primitive types.
// Program.cs
builder.Host.UseWolverine(opts =>
{
// Auto-discover handlers from this assembly
opts.Discovery.IncludeAssembly(typeof(Program).Assembly);
// RabbitMQ transport
opts.UseRabbitMq(rabbit =>
{
rabbit.HostName = "localhost";
// Or from configuration:
// rabbit.HostName = builder.Configuration["RabbitMq:Host"]!;
})
.AutoProvision() // Create queues/exchanges automatically
.AutoPurgeOnStartup(); // Dev only — clear queues on startup
// Enable transactional outbox with EF Core
opts.Services.AddDbContextWithWolverineIntegration<AppDbContext>(x =>
x.UseNpgsql(builder.Configuration.GetConnectionString("Default")));
opts.Policies.AutoApplyTransactions(); // Wrap handlers in DB transactions
});**Why**: `UseWolverine()` registers handler discovery, transport, and outbox in one place. `AutoProvision()` eliminates manual broker setup during development.
Wolverine supports two publishing styles: cascading messages (return values) and explicit publishing.
// Message contract (in shared Contracts project)
public record OrderCreated(Guid OrderId, string CustomerId, decimal Total, DateTimeOffset CreatedAt);
// Style 1: Cascading messages — return the event from the handler
// Wolverine automatically publishes returned messages after the handler completes.
public static class CreateOrder
{
public record Command(string CustomerId, List<OrderItem> Items);
public record Response(Guid OrderId, decimal Total);
public static async Task<(Response, OrderCreated)> HandleAsync(
Command command, AppDbContext db, TimeProvider clock, CancellationToken ct)
{
var order = Order.Create(command.CustomerId, command.Items, clock.GetUtcNow());
db.Orders.Add(order);
await db.SaveChangesAsync(ct);
var response = new Response(order.Id, order.Total);
var @event = new OrderCreated(order.Id, order.CustomerId, order.Total, order.CreatedAt);
return (response, @event); // Both are published automatically
}
}// Style 2: Explicit publishing via IMessageBus
public static class CreateOrder
{
public record Command(string CustomerId, List<OrderItem> Items);
public record Response(Guid OrderId, decimal Total);
public static async Task<Response> HandleAsync(
Command command, AppDbContext db, IMessageBus bus, TimeProvider clock, CancellationToken ct)
{
var order = Order.Create(command.CustomerId, command.Items, clock.GetUtcNow());
db.Orders.Add(order);
await db.SaveChangesAsync(ct);
await bus.PublishAsync(new OrderCreated(
order.Id, order.CustomerId, order.Total, order.CreatedAt));
return new Response(order.Id, order.Total);
}
}**Why**: Cascading messages (tuple return) are simpler and testable — the handler is a pure function. Use explicit `IMessageBus` when publishing is conditional or requires multiple events.
Wolverine uses convention-based handlers — no interface, no base class. Just a `Handle` method with the message type as the first parameter.
// Notifications module — handles OrderCreated from Orders module
public static class OrderCreatedHandler
{
public static async Task HandleAsync(
OrderCreated message, NotificationsDbContext db, ILogger logger, CancellationToken ct)
{
logger.LogInformation("Processing OrderCreated: {OrderId}", message.OrderId);
var notification = new OrderNotification(message.OrderId, message.CustomerId);
db.Notifications.Add(notification);
await db.SaveChangesAsync(ct);
}
}**Why**: Convention-based handlers have zero ceremony. Wolverine discovers them by signature: any public method named `Handle`/`HandleAsync`/`Consume`/`ConsumeAsync` with the message type as the first parameter.
Ensures messages are only published if the database transaction succeeds.
// 1. Register DbContext with Wolverine integration
builder.Host.UseWolverine(opts =>
{
opts.Services.AddDbContextWithWolverineIntegration<AppDbContext>(x =>
x.UseNpgsql(builder.Configuration.GetConnectionString("Default")));
opts.Policies.AutoApplyTransactions();
});
// 2. DbContext — add Wolverine outbox tables
public class AppDbContext(DbContextOptions<AppDbContext> options) : DbContext(options)
{
public DbSet<Order> Orders => Set<Order>();
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// Wolverine inbox/outbox tables — required for transactional messaAPI versioning strategies for ASP.NET Core. Covers Asp.Versioning library, URL segment,…
Architecture conformance check: verifies an existing codebase against its declared…
Architecture selection advisor for .NET applications. Asks structured questions about domain…
.NET Aspire for cloud-native orchestration. Covers AppHost configuration, service defaults,…
Authentication and authorization for ASP.NET Core. Covers JWT bearer tokens, OpenID Connect,…
Autonomous iteration loops for .NET: drive a broken build or failing test suite to green with…