dotnet-vertical-slice
10
总安装量
10
周安装量
#29025
全站排名
安装命令
npx skills add https://github.com/akires47/agent-skills --skill dotnet-vertical-slice
Agent 安装分布
claude-code
8
opencode
7
cursor
6
antigravity
4
gemini-cli
4
windsurf
3
Skill 文档
.NET 10 Vertical Slice Architecture
Organize code by feature, not by layer. Each feature is self-contained with its endpoint, request/response, validation, and handler in a single file.
Project Structure
src/
âââ Features/
â âââ Products/
â â âââ GetProduct.cs
â â âââ CreateProduct.cs
â â âââ ProductMapper.cs
â âââ Orders/
â âââ ...
âââ Shared/
â âââ Results/
â â âââ Result.cs
â â âââ Error.cs
â âââ Validation/
â âââ ValidationResult.cs
âââ Entities/
âââ Program.cs
Feature Slice Pattern
One file per operation containing everything needed:
// Features/Products/CreateProduct.cs
public static class CreateProduct
{
public sealed record Request(string Name, decimal Price);
public sealed record Response(int Id, string Name, decimal Price);
public static async Task<Result<Response>> HandleAsync(
Request request, AppDbContext db, CancellationToken ct)
{
var validation = Validate(request);
if (!validation.IsValid)
return validation.ToResult<Response>(null!);
var product = new Product { Name = request.Name, Price = request.Price };
db.Products.Add(product);
await db.SaveChangesAsync(ct);
return new Response(product.Id, product.Name, product.Price);
}
private static ValidationResult Validate(Request request) =>
ValidationExtensions.Validate()
.NotEmpty(request.Name, "Name")
.GreaterThan(request.Price, 0, "Price");
public static void MapEndpoint(IEndpointRouteBuilder app) => app
.MapPost("/api/products", async (Request request, AppDbContext db, CancellationToken ct) =>
(await HandleAsync(request, db, ct)).ToCreatedResponse(r => $"/api/products/{r.Id}"))
.WithName("CreateProduct")
.WithTags("Products");
}
Core Principles
- Result pattern only – Never throw exceptions, return
Result<T>orResult - Static handlers – Use
public static async Task<Result<T>> HandleAsync(...) - Inline validation – Validate at handler start, return early on failure
- Manual mapping – Use extension methods in
*Mapper.csfiles - Projections – Use
.Select()for queries, avoid loading full entities
References
See detailed implementations in the references/ folder:
- Result Pattern – Error types, Result class, HTTP mapping
- Validation – ValidationResult, fluent extensions
- Feature Examples – CRUD, filtering, pagination
Guidelines
- One feature = one file (endpoint + request/response + validation + handler)
- Name files by operation:
CreateProduct.cs,GetProducts.cs - Keep entities in shared folder (only cross-cutting concern)
- Use
[AsParameters]for query parameters - Group endpoints with
.WithTags()for OpenAPI