Skip to content
Back to skills

Aspnet Api Patterns

ASecurity

ASP.NET Core API patterns — controllers vs minimal API, built-in OpenAPI, middleware order, IExceptionHandler + ProblemDetails, and Asp.Versioning.

  • 5 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added May 26, 2026
developmentapi

Works with

  • api

Security analysis

A100/100

Scanned September 23, 2026

npx -y skills add zdanovichnick/dotnet-pilot --skill aspnet-api-patterns --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Aspnet Api Patterns?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Aspnet Api Patterns
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/zdanovichnick-aspnet-api-patterns/badge)](https://www.skillsdirectory.com/skills/zdanovichnick-aspnet-api-patterns)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: aspnet-api-patterns
description: ASP.NET Core API patterns — controllers vs minimal API, built-in OpenAPI, middleware order, IExceptionHandler + ProblemDetails, and Asp.Versioning.
when_to_use: Adding or changing endpoints, middleware, OpenAPI, or API versioning; deciding between controllers and minimal APIs.
---

# ASP.NET Core API Patterns

Reference for API development on ASP.NET Core 10. Authentication setup lives in
`skills/authentication/SKILL.md`; the Result → HTTP mapping and ProblemDetails details live in
`skills/error-handling/SKILL.md`.

## Controller vs Minimal API Decision

| Factor | Controllers | Minimal API |
|--------|------------|-------------|
| Team familiarity | Traditional .NET teams | Modern, lightweight preference |
| OpenAPI metadata | `[ProducesResponseType]` attributes | Inferred from `TypedResults` / `Results<...>` return types |
| Filters/middleware | Rich filter pipeline | Endpoint filters (simpler) |
| File organization | One controller per resource | Endpoint groups (`MapGroup`) |
| Native AOT | Not supported | Supported |
| Testability | Via WebApplicationFactory | Same |

## Controller Pattern

```csharp
[ApiController]
[Route("api/[controller]")]
[Produces("application/json")]
public class UsersController(IUserService userService) : ControllerBase
{
    [HttpGet("{id:int}")]
    [ProducesResponseType(typeof(UserResponse), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    public async Task<IActionResult> GetById(int id, CancellationToken ct)
    {
        var user = await userService.GetByIdAsync(id, ct);
        return user is null ? NotFound() : Ok(user);
    }

    [HttpPost]
    [ProducesResponseType(typeof(UserResponse), StatusCodes.Status201Created)]
    [ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)]
    public async Task<IActionResult> Create(CreateUserRequest request, CancellationToken ct)
    {
        var user = await userService.CreateAsync(request, ct);
        return CreatedAtAction(nameof(GetById), new { id = user.Id }, user);
    }
}
```

## OpenAPI

.NET 9+ ships document generation in `Microsoft.AspNetCore.OpenApi`; Swashbuckle is no longer in the
templates.

```csharp
builder.Services.AddOpenApi();

if (app.Environment.IsDevelopment())
    app.MapOpenApi();          // serves /openapi/v1.json
```

- `.WithOpenApi()` is deprecated in .NET 10 (ASPDEPR002). Use `WithSummary`/`WithDescription`/`WithTags`,
  or `AddOpenApiOperationTransformer` for anything else.
- `MapOpenApi()` serves the JSON only. Add a UI (e.g. Scalar) separately if you need one.

## Error Handling

Register an `IExceptionHandler` plus `AddProblemDetails()` and call `app.UseExceptionHandler()` with
no arguments. The handler class, its registration and the RFC 9457 field table are in
`skills/error-handling/SKILL.md` (Global Exception Handler). Avoid the lambda
`UseExceptionHandler(app => app.Run(...))` form: it bypasses `IProblemDetailsService`, so
`CustomizeProblemDetails` (traceId, instance) never runs.

## API Versioning (Asp.Versioning)

Packages: `Asp.Versioning.Http` (minimal APIs) or `Asp.Versioning.Mvc` (controllers), plus
`Asp.Versioning.Mvc.ApiExplorer` for per-version OpenAPI documents.

```csharp
builder.Services.AddApiVersioning(options =>
    {
        options.DefaultApiVersion = new ApiVersion(1.0);
        options.ReportApiVersions = true;
    })
    .AddApiExplorer(options => options.GroupNameFormat = "'v'VVV");   // .AddMvc() first for controllers

var orders = app.NewVersionedApi("Orders");
var v1 = orders.MapGroup("/api/v{version:apiVersion}/orders").HasApiVersion(1.0);
v1.MapGet("/{id:guid}", GetOrderV1);

var v2 = orders.MapGroup("/api/v{version:apiVersion}/orders").HasApiVersion(2.0);
v2.MapGet("/{id:guid}", GetOrderV2);
```

Controllers use `[ApiVersion(1.0)]` on the class and `[MapToApiVersion(2.0)]` on an action. Register
one OpenAPI document per version (`AddOpenApi("v1")`, `AddOpenApi("v2")`); the document names must
match the `GroupNameFormat` output.

## Middleware Order (critical)

```csharp
app.UseExceptionHandler();
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
app.UseRateLimiter();
app.MapControllers();
```

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.