Token导航 LogoToken导航TokenDH.com
开发external-servicegithub未标认证来源可访问许可证需确认审计通过

csharp-wolverinefxcsharp 狼獾 FX

Agent Skill

csharp-wolverinefx 用于处理 GitHub 仓库、Issue、Pull Request 和代码协作信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要围绕仓库状态、代码变更或协作事项进行整理时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

总安装

4,213

周安装

189

GitHub Stars

16

下载量

1,542
CodexClaudeCursorGemini CLI

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

GitHub

来源数

2

许可证

unknown

最后核验

2026-05-01

来源状态

来源可访问

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:csharp-wolverinefx(csharp 狼獾 FX)
来源仓库:https://github.com/wshaddix/dotnet-skills
仓库路径:skills/csharp-wolverinefx
安装命令:
npx skills add https://github.com/wshaddix/dotnet-skills --skill csharp-wolverinefx
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/wshaddix/dotnet-skills --skill csharp-wolverinefx

简介

用于WolverineFx消息处理框架集成,支持RabbitMQ与Azure Service Bus等传输协议。

  • 适用于事件驱动架构、CQRS模式与事务性发件箱实现场景。
  • 通过GitHub安装,自动配置Marten事件存储与批量消息处理管道。
  • 提供HTTP端点替代Minimal API/MVC的配置方案与错误重试策略设置。
  • 支持级联消息与预生成代码提升运行时性能与类型安全性。

SKILL.md

WolverineFX for.NET

When to Use This Skill

Use this skill when:

  • Building message handlers or command handlers with Wolverine
  • Creating HTTP endpoints with WolverineFx.HTTP (alternative to Minimal API/MVC)
  • Implementing event sourcing with Marten and Wolverine
  • Setting up transactional outbox pattern for reliable messaging
  • Configuring message transports (RabbitMQ, Azure Service Bus, Amazon SQS, TCP)
  • Implementing CQRS with event sourcing
  • Processing messages in batches
  • Using cascading messages for testable, pure function handlers
  • Configuring error handling and retry policies
  • Pre-generating code for optimized cold starts

Related Skills

  • efcore-patterns - Entity Framework Core patterns for data access
  • csharp-coding-standards - Modern C# patterns (records, pattern matching)
  • http-client-resilience - Polly resilience patterns (complementary)
  • background-services - Hosted services and background job patterns
  • aspire-configuration -.NET Aspire orchestration

Core Principles

  1. Low Ceremony Code - Pure functions, method injection, minimal boilerplate
  2. Cascading Messages - Return messages from handlers instead of injecting IMessageBus
  3. Transactional Outbox - Guaranteed message delivery with database transactions
  4. Code Generation - Runtime or pre-generated code for optimal performance
  5. Vertical Slice Architecture - Organize code by feature, not technical layers
  6. Pure Functions for Business Logic - Isolate infrastructure from business logic

Required NuGet Packages

Core Messaging

<PackageReference Include="Wolverine" />
<PackageReference Include="WolverineFx.Http" />

Persistence Integration

<PackageReference Include="WolverineFx.Marten" />

Transports

<PackageReference Include="WolverineFx.RabbitMQ" />
<PackageReference Include="WolverineFx.AzureServiceBus" />
<PackageReference Include="WolverineFx.Kafka" />
<PackageReference Include="WolverineFx.AmazonSQS" />

Basic Setup

Program.cs (ASP.NET Core)

using JasperFx;
using Wolverine;
using Wolverine.Http;

var builder = WebApplication.CreateBuilder(args);

builder.Host.UseWolverine(opts =>
{
    opts.Policies.AutoApplyTransactions();
    opts.Policies.UseDurableLocalQueues();
});

builder.Services.AddWolverineHttp();

var app = builder.Build();

app.MapWolverineEndpoints();

return await app.RunJasperFxCommands(args);

Message Handlers

Simple Message Handler

public record DebitAccount(long AccountId, decimal Amount);

public static class DebitAccountHandler
{
    public static void Handle(DebitAccount command, IAccountRepository repository)
    {
        repository.Debit(command.AccountId, command.Amount);
    }
}

Handler with Cascading Messages

public record CreateOrder(Guid OrderId, string[] Items);
public record OrderCreated(Guid OrderId);

public static class CreateOrderHandler
{
    public static (OrderCreated, ShipOrder) Handle(
        CreateOrder command,
        IDocumentSession session)
    {
        var order = new Order { Id = command.OrderId, Items = command.Items };
        session.Store(order);

        return (
            new OrderCreated(command.OrderId),
            new ShipOrder(command.OrderId)
        );
    }
}

Using OutgoingMessages for Multiple Messages

public static OutgoingMessages Handle(ProcessOrder command)
{
    var messages = new OutgoingMessages
    {
        new OrderProcessed(command.OrderId),
        new SendEmail(command.CustomerEmail, "Order processed"),
        new UpdateInventory(command.Items)
    };

    messages.Delay(new CleanupOrder(command.OrderId), 5.Minutes());

    return messages;
}

HTTP Endpoints (WolverineFx.HTTP)

Basic GET Endpoint

[WolverineGet("/users/{id}")]
public static Task<User?> GetUser(int id, IQuerySession session)
    => session.LoadAsync<User>(id);

POST with Message Publishing

[WolverinePost("/orders")]
public static async Task<IResult> CreateOrder(
    CreateOrderRequest request,
    IDocumentSession session,
    IMessageBus bus)
{
    var order = new Order { Id = Guid.NewGuid(), Items = request.Items };
    session.Store(order);

    await bus.PublishAsync(new OrderCreated(order.Id));

    return Results.Created($"/orders/{order.Id}", order);
}

Compound Handler (Load/Validate/Handle)

public static class UpdateOrderEndpoint
{
    public static async Task<(Order?, IResult)> LoadAsync(
        UpdateOrder command,
        IDocumentSession session)
    {
        var order = await session.LoadAsync<Order>(command.OrderId);
        return order != null
            ? (order, new WolverineContinue())
            : (order, Results.NotFound());
    }

    [WolverinePut("/orders")]
    public static void Handle(UpdateOrder command, Order order, IDocumentSession session)
    {
        order.Items = command.Items;
        session.Store(order);
    }
}

Event Sourcing with Marten

Aggregate Handler Workflow

public class Order
{
    public Guid Id { get; set; }
    public int Version { get; set; }
    public Dictionary<string, Item> Items { get; set; } = new();
    public DateTimeOffset? Shipped { get; private set; }

    public void Apply(ItemReady ready) => Items[ready.Name].Ready = true;
    public void Apply(IEvent<OrderShipped> shipped) => Shipped = shipped.Timestamp;

    public bool IsReadyToShip() => Shipped == null && Items.Values.All(x => x.Ready);
}

public record MarkItemReady(Guid OrderId, string ItemName, int Version);

[AggregateHandler]
public static IEnumerable<object> Handle(MarkItemReady command, Order order)
{
    if (order.Items.TryGetValue(command.ItemName, out var item))
    {
        item.Ready = true;
        yield return new ItemReady(command.ItemName);
    }

    if (order.IsReadyToShip())
    {
        yield return new OrderReady();
    }
}

Read Aggregate (Read-Only)

[WolverineGet("/orders/{id}")]
public static Order GetOrder([ReadAggregate] Order order) => order;

Write Aggregate with Validation

public static IEnumerable<object> Handle(
    MarkItemReady command,
    [WriteAggregate(Required = true, OnMissing = OnMissing.ProblemDetailsWith404)] Order order)
{
    order.Items[command.ItemName].Ready = true;
    yield return new ItemReady(command.ItemName);
}

Returning Updated Aggregate

[AggregateHandler]
public static (UpdatedAggregate, Events) Handle(
    MarkItemReady command,
    Order order)
{
    var events = new Events();
    events.Add(new ItemReady(command.ItemName));
    return (new UpdatedAggregate(), events);
}

Transactional Outbox

Marten Integration

builder.Services.AddMarten(opts =>
{
    opts.Connection(connectionString);
}).IntegrateWithWolverine();

builder.Host.UseWolverine(opts =>
{
    opts.Policies.AutoApplyTransactions();
});

Using Outbox in Controllers

[HttpPost("/orders")]
public async Task Post(
    [FromBody] CreateOrder command,
    [FromServices] IDocumentSession session,
    [FromServices] IMartenOutbox outbox)
{
    outbox.Enroll(session);

    var order = new Order { Id = command.OrderId };
    session.Store(order);

    await outbox.PublishAsync(new OrderCreated(command.OrderId));

    await session.SaveChangesAsync();
}

Transport Configuration

RabbitMQ

builder.Host.UseWolverine(opts =>
{
    opts.UseRabbitMq("host=localhost")
        .AutoProvision()
        .AutoPurgeOnStartup();

    opts.PublishAllMessages()
        .ToRabbitExchange("wolverine.events", exchange =>
        {
            exchange.ExchangeType = ExchangeType.Topic;
        });
});

Azure Service Bus

builder.Host.UseWolverine(opts =>
{
    opts.UseAzureServiceBus(asbConnectionString)
        .AutoProvision()
        .ConfigureQueue(q => q.MaxDeliveryCount = 5);
});

Amazon SQS

builder.Host.UseWolverine(opts =>
{
    opts.UseAmazonSqs(sqsConfig)
        .AutoProvision();
});

Batch Message Processing

Configure Batching

builder.Host.UseWolverine(opts =>
{
    opts.BatchMessagesOf<SubTaskCompleted>(batching =>
    {
        batching.BatchSize = 500;
        batching.TriggerTime = 1.Seconds();
    });
});

Batch Handler

public static class ItemBatchHandler
{
    public static void Handle(Item[] items, IRepository repository)
    {
        foreach (var item in items)
        {
            repository.Process(item);
        }
    }
}

Custom Batching Strategy

public record SubTaskCompleted(string TaskId, string SubTaskId);
public record SubTaskBatch(string TaskId, string[] SubTaskIds);

public class SubTaskBatcher : IMessageBatcher
{
    public IEnumerable<Envelope> Group(IReadOnlyList<Envelope> envelopes)
    {
        var groups = envelopes
            .GroupBy(x => x.Message!.As<SubTaskCompleted>().TaskId);

        foreach (var group in groups)
        {
            var subTaskIds = group
                .Select(x => x.Message)
                .OfType<SubTaskCompleted>()
                .Select(x => x.SubTaskId)
                .ToArray();

            yield return new Envelope(
                new SubTaskBatch(group.Key, subTaskIds),
                group);
        }
    }

    public Type BatchMessageType => typeof(SubTaskBatch);
}

Error Handling

Retry Policies

builder.Host.UseWolverine(opts =>
{
    opts.Policies.OnException<SqlException>()
        .RetryWithCooldown(50.Milliseconds(), 100.Milliseconds(), 250.Milliseconds());

    opts.Policies.OnException<TimeoutException>()
        .RetryTimes(3);

    opts.Policies.OnException<InvalidOperationException>()
        .Requeue();

    opts.Policies.OnAnyException()
        .MoveToErrorQueue();
});

Circuit Breaker

opts.ListenToRabbitQueue("incoming")
    .CircuitBreaker(cb =>
    {
        cb.PauseTime = 1.Minutes();
        cb.FailurePercentageThreshold = 50;
        cb.MinimumThreshold = 10;
    });

Scheduled Messages

Delayed Messages

public static IEnumerable<object> Handle(OrderCreated command)
{
    yield return new ProcessPayment(command.OrderId);
    yield return new ShipOrder(command.OrderId)
        .DelayedFor(30.Minutes());
}

Scheduled at Specific Time

yield return new GenerateReport()
    .ScheduledAt(DateTime.Today.AddDays(1));

Using OutgoingMessages

var messages = new OutgoingMessages();
messages.Delay(new Reminder(orderId), TimeSpan.FromHours(24));
messages.Schedule(new MonthlyReport(), DateTime.Today.AddMonths(1));

Request/Reply Pattern

Sending with Response Request

public async Task<OrderStatus> GetOrderStatus(IMessageBus bus, Guid orderId)
{
    return await bus.InvokeAsync<OrderStatus>(new GetOrder(orderId));
}

Handler with Response

public record GetOrder(Guid OrderId);
public record OrderStatus(Guid OrderId, string Status);

public static class GetOrderHandler
{
    public static OrderStatus Handle(GetOrder query, IQuerySession session)
    {
        var order = session.Load<Order>(query.OrderId);
        return new OrderStatus(query.OrderId, order?.Status ?? "NotFound");
    }
}

Middleware

Custom Middleware

public class LoggingMiddleware
{
    public void Before(Envelope envelope, ILogger logger)
    {
        logger.LogInformation("Processing {MessageType}", envelope.MessageType);
    }

    public void After(Envelope envelope, ILogger logger)
    {
        logger.LogInformation("Completed {MessageType}", envelope.MessageType);
    }
}

builder.Host.UseWolverine(opts =>
{
    opts.Handlers.AddMiddleware<LoggingMiddleware>();
});

Transaction Middleware

builder.Host.UseWolverine(opts =>
{
    opts.Policies.AutoApplyTransactions();
});

Code Generation

Pre-Generate Types

dotnet run -- codegen write

Generated code appears in ./Internal/Generated/WolverineHandlers/

Configure for AOT/Trimming

builder.Host.UseWolverine(opts =>
{
    opts.CodeGeneration.TypeLoadMode = TypeLoadMode.Auto;
});

Multi-Tenancy

Conjoined Tenancy

builder.Host.UseWolverine(opts =>
{
    opts.Policies.ConjoinedTenancy(x =>
    {
        x.TenantIdStyle = TenantIdStyle.PerRequest;
    });
});

Publishing to Specific Tenant

await bus.PublishAsync(new OrderCreated(orderId),
    new DeliveryOptions { TenantId = "tenant-1" });

Marten Side Effects

public static IMartenOp Handle(CreateTodo command)
{
    var todo = new Todo { Name = command.Name };
    return MartenOps.Store(todo);
}

public static IMartenOp Handle(DeleteTodo command)
{
    return MartenOps.Delete<Todo>(command.Id);
}

Ancillary Stores (Modular Monolith)

public interface IPlayerStore : IDocumentStore;

builder.Host.UseWolverine(opts =>
{
    opts.Services.AddMartenStore<IPlayerStore>(m =>
    {
        m.Connection(connectionString);
        m.DatabaseSchemaName = "players";
    })
    .IntegrateWithWolverine();
});

[MartenStore(typeof(IPlayerStore))]
public static class PlayerMessageHandler
{
    public static IMartenOp Handle(PlayerMessage message)
    {
        return MartenOps.Store(new Player { Id = message.Id });
    }
}

Command Line Tools

Available Commands

dotnet run -- help           # List all commands
dotnet run -- describe       # Application description
dotnet run -- resources      # Resource management
dotnet run -- storage        # Message storage admin
dotnet run -- codegen write  # Pre-generate code

Best Practices

  1. Prefer pure functions - Business logic should be testable without mocks
  2. Use cascading messages - Return messages instead of injecting IMessageBus
  3. Keep call stacks short - Avoid deep service hierarchies
  4. Pre-generate code - Optimize cold starts in production
  5. Use compound handlers - Separate load/validate/handle logic
  6. Configure error handling - Let Wolverine handle retries and errors
  7. Use transactional outbox - Guarantee message delivery
  8. Batch when appropriate - Improve throughput for high-volume messages

Anti-Patterns to Avoid

  1. Injecting IMessageBus deep in call stack - Makes workflow hard to reason about
  2. Over-using constructor injection - Prefer method injection
  3. Ignoring transactional outbox - Can lose messages on failure
  4. Not pre-generating code - Slow cold starts in production
  5. Mixing too many concerns in one handler - Keep handlers focused
  6. Not configuring error handling - Messages end up in error queue unexpectedly

适合场景

01

用户想查找某类 Agent Skill 时

02

需要根据任务场景推荐可安装能力包时

03

需要对比不同来源的安装命令和来源信息时

能力概览

能力 1

按任务关键词查找相关 Skills

能力 2

展示可复制的安装命令

能力 3

保留来源站点、仓库和原始说明,方便继续核验

能力 4

展示第三方安全扫描或审计结果

安装后应在对应宿主中按原始 README 的触发条件使用;具体调用方式请以来源页面和 README 为准。

平台分布

Codex

37.19%
按下载量换算573

Claude

27.79%
按下载量换算429

Cursor

19.59%
按下载量换算302

Gemini CLI

9.45%
按下载量换算146

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

通过

权限和风险

external-service

该 Skill 可能调用第三方服务、云服务或外部模型 API,使用前需要确认账号、额度、数据发送范围和服务条款。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。当前只有一个来源,正式发布前建议补源仓库或其他目录站核验。

来源信息

继续浏览同类 Skills