agentleFS
linuxchatalinuxchata/ai-playbook/.claude/skills/csharp-api-controller-standards/SKILL.md

csharp-api-controller-standards

Skill6 starsChanged 6 months agoMITView on GitHub

Defines the coding standards, patterns, and conventions for ASP.NET Core REST API controllers. Rules cover routing, HTTP verbs, response types, XML documentation, dependency injection, and asynchronous execution. Apply these rules uniformly to ensure a consistent, predictable, and well-documented API surface.

The file

Show its rules and text

We split this skill into the rules it gives an agent

13 rules. About 0 are common, 6 are distinctive, and 7 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈6

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 7

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    All API controllers must inherit from ControllerBase (not Controller, which includes view rendering logic).

    line 20
  2. Very specific:

    Use the [Route] attribute at the class level to define the base path.

    line 22
  3. Distinctive:

    Use nouns, not verbs, for endpoint paths.

    line 42
  4. Very specific:

    Prefer [controller] in the Route attribute to automatically use the controller name (minus the "Controller" suffix).

    line 43
  5. Distinctive:

    Use the correct HTTP verb corresponding to the operation:

    line 61
  6. Very specific:

    Use the built-in helper methods (Ok(), Created(), NotFound(), BadRequest(), NoContent()) to generate responses.

    line 94
  7. Distinctive:

    Always return the appropriate HTTP status code for the outcome:

    line 98
  8. Distinctive:

    Every controller action must be fully documented using XML comments.

    line 135
  9. Distinctive:

    Always use constructor injection for services required by the controller.

    line 168
  10. Very specific:

    All controller actions must be async Task<IActionResult> or async Task<ActionResult<T>>.

    line 209
  11. Very specific:

    Always append the Async suffix to the action method name.

    line 210
  12. Very specific:

    Every action must accept a CancellationToken as its final parameter and pass it down to all async service calls.

    line 211
  13. Distinctive:

    Before submitting an API controller, verify:

    line 229

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

C# ASP.NET Core API Controller Standards

Description

Defines the coding standards, patterns, and conventions for ASP.NET Core REST API controllers. Rules cover routing, HTTP verbs, response types, XML documentation, dependency injection, and asynchronous execution. Apply these rules uniformly to ensure a consistent, predictable, and well-documented API surface.


1. Controller Structure & Inheritance

1.1 Base Class and Attributes

  • All API controllers must inherit from ControllerBase (not Controller, which includes view rendering logic).
  • Decorate all controllers with the [ApiController] attribute to enable automatic model validation, API behavior conventions, and attribute routing requirements.
  • Use the [Route] attribute at the class level to define the base path.
// ✅ Correct
[ApiController]
[Route("api/[controller]")]
public sealed class OrdersController : ControllerBase
{
}

// ❌ Wrong
public class OrdersController : Controller { }

2. Routing Conventions

2.1 Resource Naming

  • Use nouns, not verbs, for endpoint paths.
  • Prefer [controller] in the Route attribute to automatically use the controller name (minus the "Controller" suffix).

2.2 Route Parameters

  • Specify route parameters explicitly in the HTTP verb attributes.
  • Match route parameter names exactly with the method parameter names.
[HttpGet("{id:guid}")]
public async Task<IActionResult> GetByIdAsync(Guid id, CancellationToken cancellationToken)

3. HTTP Methods & Attributes

3.1 Standard Verbs

Use the correct HTTP verb corresponding to the operation:

VerbUsageIdempotent
[HttpGet]Retrieve a resource or collectionYes
[HttpPost]Create a new resource or execute an actionNo
[HttpPut]Fully update an existing resourceYes
[HttpPatch]Partially update an existing resourceNo
[HttpDelete]Remove a resourceYes

3.2 Action Parameters Binding

Explicitly state where parameters are bound from to avoid ambiguity and improve OpenAPI generation:

  • [FromRoute]: For IDs and path segments.
  • [FromQuery]: For filtering, paging, and sorting parameters.
  • [FromBody]: For complex objects in POST/PUT/PATCH requests.
[HttpGet("{id:guid}/items")]
public async Task<IActionResult> GetItemsAsync(
    [FromRoute] Guid id, 
    [FromQuery] int page, 
    CancellationToken cancellationToken)

4. Responses & Status Codes

4.1 Explicit Action Results

  • Return IActionResult or ActionResult<T>.
  • Use the built-in helper methods (Ok(), Created(), NotFound(), BadRequest(), NoContent()) to generate responses.

4.2 Standard Status Codes

Always return the appropriate HTTP status code for the outcome:

  • 200 OK: Successful GET.
  • 201 Created: Successful POST that creates a resource. Might include a Location header pointing to the new resource.
  • 204 No Content: Successful operation that returns no body (e.g., DELETE, PUT, PATCH).
  • 400 Bad Request: Client error (validation failure, invalid input).
  • 401 Unauthorized: Authentication required.
  • 403 Forbidden: Authenticated, but lacks permission.
  • 404 Not Found: The requested resource ID does not exist.
  • 409 Conflict: Resource state conflict (e.g., trying to create a duplicate).
[HttpPost]
public async Task<IActionResult> CreateAsync([FromBody] CreateOrderRequest request, CancellationToken cancellationToken)
{
    var id = await _service.CreateAsync(request, cancellationToken);
    return CreatedAtAction(nameof(GetByIdAsync), new { id = id }, request);
}

4.3 [ProducesResponseType]

Explicitly declare all possible status codes and their corresponding return types using [ProducesResponseType]. This is critical for generating accurate OpenAPI/Swagger documentation.

[HttpGet("{id:guid}")]
[ProducesResponseType(typeof(OrderDto), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<IActionResult> GetByIdAsync([FromRoute] Guid id, CancellationToken cancellationToken)

5. XML Documentation

5.1 Public API Contracts

Every controller action must be fully documented using XML comments.

XML comment tags:

  • <summary>: A brief, single-sentence description of what the endpoint does.
  • <remarks>: (Optional) Detailed information, usage examples, or nuances.
  • <param>: Description of each input parameter.
  • <returns>: Description of the HTTP response.
  • <response>: Description of each possible HTTP status code returned.
/// <summary>
/// Retrieves a specific order by its unique identifier.
/// </summary>
/// <param name="id">The unique identifier of the order.</param>
/// <param name="cancellationToken">A cancellation token.</param>
/// <returns>The HTTP response.</returns>
/// <response code="200">A specific order.</response>
/// <response code="404">If the order is not found.</response>
[HttpGet("{id:guid}")]
[ProducesResponseType(typeof(OrderDto), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<IActionResult> GetByIdAsync([FromRoute] Guid id, CancellationToken cancellationToken)
{
    // ... implementation
}

6. Dependency Injection

6.1 Constructor Injection

Always use constructor injection for services required by the controller.

If using C# 12 or later, prefer Primary Constructors to eliminate boilerplate:

// ✅ Correct (C# 12+)
[ApiController]
[Route("api/[controller]")]
public sealed class OrdersController(
    IOrderService orderService, 
    ILogger<OrdersController> logger) : ControllerBase
{
    // Dependencies are available directly as parameters
}

If using C# 11 or earlier, store dependencies in private readonly fields and use a traditional constructor:

// ✅ Correct (C# 11 and earlier)
[ApiController]
[Route("api/[controller]")]
public sealed class OrdersController : ControllerBase
{
    private readonly IOrderService _orderService;
    private readonly ILogger<OrdersController> _logger;

    public OrdersController(IOrderService orderService, ILogger<OrdersController> logger)
    {
        _orderService = orderService;
        _logger = logger;
    }
}

7. Asynchronous Execution

7.1 Async All The Way

  • All controller actions must be async Task<IActionResult> or async Task<ActionResult<T>>.
  • Always append the Async suffix to the action method name. ASP.NET Core routing automatically removes the Async suffix when mapping route names (e.g., CreatedAtAction).
  • Every action must accept a CancellationToken as its final parameter and pass it down to all async service calls.
// ✅ Correct
[HttpDelete("{id:guid}")]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<IActionResult> DeleteAsync([FromRoute] Guid id, CancellationToken cancellationToken)
{
    var result = await _orderService.DeleteAsync(id, cancellationToken);
    return result ? NoContent() : NotFound();
}

Quick Reference Checklist

Before submitting an API controller, verify:

  • Inherits from ControllerBase and has [ApiController] and [Route] attributes
  • Route uses plural nouns (e.g., api/users)
  • Correct HTTP verb attribute used ([HttpGet], [HttpPost], etc.)
  • Input parameters have explicit binding attributes ([FromRoute], [FromBody], etc.)
  • Action is async Task<IActionResult> and method name ends with Async
  • CancellationToken is the last parameter and is passed down
  • XML <summary>, <param>, and <response> tags are complete
  • [ProducesResponseType] covers all possible HTTP status codes returned
  • Returns correct standard HTTP status codes (200, 201, 204, 400, 404, etc.)

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.