Messaging

codewithmukesh/dotnet-claude-kit/skills/messaging

作者 codewithmukesh23300897f4d1無授權條款754 個星標收錄於 2026年10月8日更新於 2026年10月8日儲存庫2 個月前更新

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".

AI 產生的概覽

適用於 .NET 應用程式的非同步訊息傳遞指南,涵蓋 Wolverine、MassTransit、寄件匣、Saga 與訊息代理程式設定。

功能
此技能為 .NET 應用程式中的非同步訊息傳遞提供參考模式與程式碼範例。內容涵蓋 Wolverine 與 MassTransit 的設定、事件的發佈與取用、交易式寄件匣模式、Saga 與編排的取捨,以及 RabbitMQ 和 Azure Service Bus 的代理程式設定。它也列出反模式並提供方案選擇的決策指南。此技能僅為說明性內容,不會產生檔案或指令碼。
適用情境
適用於在 .NET 中實作事件驅動通訊、背景處理或模組間訊息傳遞的情境。當涉及 Wolverine、MassTransit、RabbitMQ、Azure Service Bus、寄件匣、Saga、佇列或發佈訂閱時也適用。
執行需求
不含指令碼或隨附資源,除代理程式本身外不需其他工具。其指引假定已有使用 Wolverine 或 MassTransit 的 .NET 專案、EF Core,以及 RabbitMQ 或 Azure Service Bus 等訊息代理程式,並需要這些服務所需的認證與網路存取。

Messaging

Core Principles

  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.

Patterns

Wolverine Setup

csharp
// Program.csbuilder.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.

Publishing Events

Wolverine supports two publishing styles: cascading messages (return values) and explicit publishing.

csharp
// 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    }}
csharp
// Style 2: Explicit publishing via IMessageBuspublic 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.

Consuming Events

Wolverine uses convention-based handlers — no interface, no base class. Just a Handle method with the message type as the first parameter.

csharp
// Notifications module — handles OrderCreated from Orders modulepublic 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.

Transactional Outbox

Ensures messages are only published if the database transaction succeeds.

csharp
// 1. Register DbContext with Wolverine integrationbuilder.Host.UseWolverine(opts =>{    opts.Services.AddDbContextWithWolverineIntegration<AppDbContext>(x =>        x.UseNpgsql(builder.Configuration.GetConnectionString("Default")));
    opts.Policies.AutoApplyTransactions();});
// 2. DbContext — add Wolverine outbox tablespublic 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 messaging        modelBuilder.AddIncomingWolverineMessageTable();        modelBuilder.AddOutgoingWolverineMessageTable();    }}

Why: AddDbContextWithWolverineIntegration + AutoApplyTransactions wraps every handler in a transaction that includes outbox writes. Messages are only sent after the transaction commits — no dual-write problem.

Saga (Stateful Orchestration)

Wolverine sagas use a Saga<T> base class with Start and Handle methods. Cascading messages drive the saga forward.

csharp
public record OrderSagaState(Guid Id){    public string? CustomerId { get; set; }    public bool PaymentReceived { get; set; }}
public class OrderSaga : Saga<OrderSagaState>{    public Guid Id { get; set; }
    // Start the saga when an OrderCreated event arrives    public static (OrderSagaState, ProcessPayment) Start(OrderCreated message)    {        var state = new OrderSagaState(message.OrderId)        {            CustomerId = message.CustomerId        };
        var command = new ProcessPayment(message.OrderId, message.Total);        return (state, command); // State is persisted, command is sent    }
    // Handle payment result    public CompleteOrder Handle(PaymentCompleted message)    {        PaymentReceived = true;        MarkCompleted(); // Ends the saga        return new CompleteOrder(Id);    }
    // Compensating action on failure    public CancelOrder Handle(PaymentFailed message)    {        MarkCompleted();        return new CancelOrder(Id);    }}

Why: Wolverine sagas use simple C# methods instead of a state machine DSL. Each handler returns cascading messages to drive the workflow. MarkCompleted() cleans up the saga state.

Alternative: MassTransit

MassTransit is a mature alternative with a commercial license requirement from v9+. Key API surface:

csharp
// Setupbuilder.Services.AddMassTransit(x =>{    x.SetKebabCaseEndpointNameFormatter();    x.AddConsumers(typeof(Program).Assembly);    x.UsingRabbitMq((context, cfg) =>    {        cfg.Host(builder.Configuration.GetConnectionString("RabbitMq"));        cfg.ConfigureEndpoints(context);    });});
// Publishingawait publishEndpoint.Publish(new OrderCreated(...), ct);
// Consuming — requires IConsumer<T> interfacepublic class OrderCreatedConsumer(AppDbContext db) : IConsumer<OrderCreated>{    public async Task Consume(ConsumeContext<OrderCreated> context)    {        var message = context.Message;        // Handle event...    }}
// Outboxx.AddEntityFrameworkOutbox<AppDbContext>(o =>{    o.UsePostgres();    o.UseBusOutbox();});
// Saga — uses MassTransitStateMachine<TState>public class OrderSaga : MassTransitStateMachine<OrderSagaState> { /* ... */ }

License note: MassTransit v9+ requires a commercial license for production use. Wolverine (MIT) is the recommended default for new projects.

Anti-patterns

Don't Publish Events Without Outbox

csharp
// BAD — if SaveChanges succeeds but Publish fails, data is inconsistentawait db.SaveChangesAsync(ct);await bus.PublishAsync(new OrderCreated(...));
// GOOD — use transactional outbox (messages are in the same transaction)// Configure AddDbContextWithWolverineIntegration() + AutoApplyTransactions()// Wolverine handles this automatically

Don't Put Complex Logic in Message Contracts

csharp
// BAD — behavior in a messagepublic record OrderCreated(Guid OrderId){    public decimal CalculateShipping() => /* logic */; // DON'T}
// GOOD — messages are pure datapublic record OrderCreated(Guid OrderId, string CustomerId, decimal Total, DateTimeOffset CreatedAt);

Don't Use Fire-and-Forget for Important Events

csharp
// BAD — no guarantee of delivery_ = Task.Run(() => bus.PublishAsync(new OrderCreated(...)));
// GOOD — await the publish (with outbox, this is transactional)await bus.PublishAsync(new OrderCreated(...));

Decision Guide

ScenarioRecommendation
Module-to-module communication (new project)Wolverine with events (MIT, free)
Module-to-module communication (existing MassTransit)MassTransit (commercial license required from v9)
Reliable event publishingTransactional outbox (both Wolverine and MassTransit support this)
Simple 2-3 step workflowEvent choreography
Complex workflow with compensationWolverine saga or MassTransit saga
Local development brokerRabbitMQ (via Docker or Aspire)
Production cloud brokerAzure Service Bus or RabbitMQ
Want single lib for mediator + messagingWolverine (replaces both Mediator and MassTransit)

來源與署名

來源:codewithmukesh/dotnet-claude-kit位於skills/messaging提交2330089

授權條款: 無授權條款

內容歸原作者所有。SourceWeft 從公開儲存庫中收錄這些內容。

檢舉或申請下架

更多來自 codewithmukesh/dotnet-claude-kit 的技能

Wrap Up

codewithmukesh

在 session 結束時把已完成工作、待辦事項與經驗寫入交接檔案,並在 session 開始時重新載入。

Productivity & Workflow7542 個月前更新

Workflow Mastery

codewithmukesh

Claude Code workflow mastery for .NET developers. Covers parallel execution with git worktrees, plan mode strategy, verification loops, auto-formatting hooks, permission setup for dotnet CLI, prompting techniques, subagent patterns, and context discipline — token budget management, MCP-first navigation, lazy loading, and subagent isolation — all adapted for the .NET ecosystem. Load this skill when setting up Claude Code for a .NET project, optimizing workflows, running parallel sessions, when context is running low or sessions feel sluggish, when exploring a large codebase efficiently, or when the user mentions "productivity", "workflow", "parallel", "worktree", "plan mode", "permissions", "hooks", "10x", "setup Claude Code", "speed up development", "context", "tokens", "budget", "running out of context", "too many files", or "large codebase". Inspired by tips from Boris Cherny (creator of Claude Code) and the Anthropic team.

待分類7542 個月前更新

Vertical Slice

codewithmukesh

指導 .NET 開發者以垂直切片架構組織應用程式,涵蓋功能資料夾、端點分組與處理常式模式。

Software Development7542 個月前更新

Testing

codewithmukesh

Testing strategy for .NET 10 applications. Covers xUnit v3, WebApplicationFactory for integration tests, Testcontainers for real database testing, Verify for snapshot testing, and the AAA pattern. Load this skill when writing tests, setting up test infrastructure, reviewing test coverage, or when the user mentions "test", "xUnit", "WebApplicationFactory", "Testcontainers", "integration test", "unit test", "bUnit", "snapshot test", "Verify", "test coverage", "AAA pattern", "WireMock", or "FakeTimeProvider".

待分類7542 個月前更新

Tdd

codewithmukesh

Guided test-driven development workflow for .NET 10 using xUnit v3, WebApplicationFactory, Testcontainers, and Verify snapshots. Follows the strict red-green-refactor cycle. Use when: "TDD", "test-driven", "let's TDD this", "red green refactor", "write the test first", or when building a feature with clear acceptance criteria.

待分類7542 個月前更新

Spec

codewithmukesh

透過結構化提問,把模糊的功能想法轉化為雙方確認並持久化的規格文件。

Productivity & Workflow7542 個月前更新