用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/rudironsoni/Synaxis --skill dotnet-minimal-apis命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
正在显示 SKILL.md
Routes .NET/C# work to domain skills. Loads coding-standards for code paths.
基于 SOC 职业分类
| name | dotnet-minimal-apis |
| description | Builds ASP.NET Core Minimal APIs -- route groups, filters, TypedResults, OpenAPI. |
| metadata | {"short-description":".NET skill guidance for web tasks"} |
Minimal APIs are Microsoft's recommended approach for new ASP.NET Core HTTP API projects. They provide a lightweight, lambda-based programming model with first-class OpenAPI support, endpoint filters for cross-cutting concerns, and route groups for organization at scale.
Cross-references: [skill:dotnet-architecture-patterns] for organizing large APIs, [skill:dotnet-input-validation] for request validation, [skill:dotnet-api-versioning] for versioning strategies, [skill:dotnet-openapi] for OpenAPI customization.
Route groups organize related endpoints under a shared prefix, applying common configuration (filters, metadata,
authorization) once. They replace repetitive chaining of MapGet/MapPost with shared prefixes.
var app = builder.Build();
// Group endpoints under /api/products with shared configuration
var products = app.MapGroup("/api/products")
.WithTags("Products")
.RequireAuthorization();
products.MapGet("/", async (AppDbContext db) =>
TypedResults.Ok(await db.Products.ToListAsync()));
products.MapGet("/{id:int}", async (int id, AppDbContext db) =>
await db.Products.FindAsync(id) is Product product
? TypedResults.Ok(product)
: TypedResults.NotFound());
products.MapPost("/", async (CreateProductDto dto, AppDbContext db) =>
{
var product = new Product { Name = dto.Name, Price = dto.Price };
db.Products.Add(product);
await db.SaveChangesAsync();
return TypedResults.Created($"/api/products/{product.Id}", product);
});
products.MapDelete("/{id:int}", async (int id, AppDbContext db) =>
{
if (await db.Products.FindAsync(id) is not Product product)
return TypedResults.NotFound();
db.Products.Remove(product);
await db.SaveChangesAsync();
return TypedResults.NoContent();
});
```text
### Nested Groups
Groups can be nested to compose prefixes and filters:
```csharp
var api = app.MapGroup("/api")
.AddEndpointFilter<RequestLoggingFilter>();
var v1 = api.MapGroup("/v1");
var products = v1.MapGroup("/products").WithTags();
orders = v1.MapGroup().WithTags();
products.MapGet(, GetProducts);
orders.MapPost(, CreateOrder);
```text
---
Endpoint filters provide a pipeline cross-
{
ValueTask<?> InvokeAsync(
EndpointFilterInvocationContext context,
EndpointFilterDelegate next)
{
argument = context.Arguments
.OfType<T>()
.FirstOrDefault();
(argument )
TypedResults.BadRequest();
result = validator.ValidateAsync(argument);
(!result.IsValid)
{
TypedResults.ValidationProblem(
result.ToDictionary());
}
next(context);
}
}
```text
```csharp
products.MapPost(, CreateProduct)
.AddEndpointFilter<ValidationFilter<CreateProductDto>>();
products = app.MapGroup()
.AddEndpointFilter<RequestLoggingFilter>();
products.MapGet(, GetProductById)
.AddEndpointFilter( (context, next) =>
{
id = context.GetArgument<>();
(id <= )
TypedResults.BadRequest();
next(context);
});
```text
=>
db.Products.FindAsync(id) Product product
? TypedResults.Ok(product)
: TypedResults.NotFound());
products.MapGet(, ( id, AppDbContext db) =>
db.Products.FindAsync(id) Product product
? Results.Ok(product)
: Results.NotFound());
```text
Use `Results<T1, T2, ...>` to declare all possible response types a single endpoint. This enables accurate OpenAPI
documentation multiple response codes:
```csharp
products.MapPost(, =>
{
( db.Products.AnyAsync(p => p.Sku == dto.Sku))
TypedResults.Conflict();
product = Product { Name = dto.Name, Sku = dto.Sku, Price = dto.Price };
db.Products.Add(product);
db.SaveChangesAsync();
TypedResults.Created(, product);
});
```text
---
.NET adds built- OpenAPI support via `Microsoft.AspNetCore.OpenApi`. Minimal APIs generate OpenAPI metadata
`TypedResults`, parameter bindings, attributes automatically.
```csharp
builder.Services.AddOpenApi();
app = builder.Build();
(app.Environment.IsDevelopment())
{
app.MapOpenApi();
}
```json
```csharp
products.MapGet(, GetProductById)
.WithName()
.WithSummary()
.WithDescription()
.Produces<Product>(StatusCodes.Status200OK)
.ProducesProblem(StatusCodes.Status404NotFound);
```
{
{
= routes.MapGroup()
.WithTags();
.MapGet(, GetAll);
.MapGet(, GetById);
.MapPost(, Create);
.MapPut(, Update);
.MapDelete(, Delete);
;
}
Task<Ok<List<Product>>> GetAll(AppDbContext db) =>
TypedResults.Ok( db.Products.ToListAsync());
Task<Results<Ok<Product>, NotFound>> GetById(
id, AppDbContext db) =>
db.Products.FindAsync(id) Product p
? TypedResults.Ok(p)
: TypedResults.NotFound();
Task<Created<Product>> Create(
CreateProductDto dto, AppDbContext db)
{
product = Product { Name = dto.Name, Price = dto.Price };
db.Products.Add(product);
db.SaveChangesAsync();
TypedResults.Created(, product);
}
Task<Results<NoContent, NotFound>> Update(
id, UpdateProductDto dto, AppDbContext db)
{
product = db.Products.FindAsync(id);
(product ) TypedResults.NotFound();
product.Name = dto.Name;
product.Price = dto.Price;
db.SaveChangesAsync();
TypedResults.NoContent();
}
Task<Results<NoContent, NotFound>> Delete(
id, AppDbContext db)
{
product = db.Products.FindAsync(id);
(product ) TypedResults.NotFound();
db.Products.Remove(product);
db.SaveChangesAsync();
TypedResults.NoContent();
}
}
app.MapProductEndpoints();
app.MapOrderEndpoints();
app.MapCustomerEndpoints();
```csharp
For projects that prefer auto-discovery of endpoint modules, the Carter library provides an `ICarterModule` :
```
:
{
{
= app.MapGroup().WithTags();
.MapGet(, (AppDbContext db) =>
TypedResults.Ok( db.Products.ToListAsync()));
.MapGet(, ( id, AppDbContext db) =>
db.Products.FindAsync(id) Product p
? TypedResults.Ok(p)
: TypedResults.NotFound());
}
}
builder.Services.AddCarter();
app = builder.Build();
app.MapCarter();
```csharp
;
});
```json
**Gotcha:** `ConfigureHttpJsonOptions` configures JSON serialization Minimal APIs only. MVC controllers use a
separate pipeline -- configure via `builder.Services.AddControllers().AddJsonOptions(...)`. Mixing them up has no
effect.
---
Minimal APIs bind parameters route, query, headers, body, DI automatically based type attribute
annotations.
```csharp
app.MapGet(, ( id) => ...);
app.MapGet(, ([FromQuery] page, [FromQuery] pageSize) => ...);
app.MapGet(, ([FromHeader(Name = )] correlationId) => ...);
app.MapPost(, (CreateProductDto dto) => ...);
app.MapGet(, (AppDbContext db, ILogger<Program> logger) => ...);
app.MapGet(, ([AsParameters] ProductQuery query) => ...);
;
```text
---
**Do use `Results` `TypedResults` available** -- `Results.Ok()` returns `IResult` the OpenAPI
generator cannot infer response schemas. Use `TypedResults.Ok()` to enable automatic schema generation.
**Do forget `ConfigureHttpJsonOptions` only applies to Minimal APIs** -- MVC controllers need
`.AddControllers().AddJsonOptions()` separately.
**Do apply validation logic inline every endpoint** -- use endpoint filters cross-reference
[] centralized validation patterns.
**Do register filters the wrong order** -- first-registered filter outermost.
Primary approach: Use Serena symbol operations for efficient code navigation:
serena_find_symbol instead of text searchserena_get_symbols_overview for file organizationserena_find_referencing_symbols for impact analysisserena_replace_symbol_body for clean modificationsWhen to use Serena vs traditional tools:
Example workflow:
# Instead of:
Read: src/Services/OrderService.cs
Grep: "public void ProcessOrder"
# Use:
serena_find_symbol: "OrderService/ProcessOrder"
serena_get_symbols_overview: "src/Services/OrderService.cs"