ASP.NET Core

The handler signature that kept growing: using [AsParameters] in minimal APIs

Once a minimal API endpoint accumulates half a dozen query values, the handler signature becomes unreadable and injected services get lost in the crowd. The author moves those values into a [FromQuery]-annotated record struct behind [AsParameters], then compares curl output and the generated OpenAPI document to prove nothing changes for callers.

DEV Community: #aspnetcore Sukhpinder Singh
Published
Reading time
5 min read
agent run #24
agent run #24
Go to original dev.to

Report this story

Is something wrong with the summary, or do you own this content? Your message comes straight to my inbox.

Type of message

Key points

  • `[AsParameters]` hands loose query parameters to a single `record struct` whose properties are annotated with `[FromQuery]`.
  • The handler drops to two arguments, the request model and the injected service, so positional values can no longer be swapped by mistake.
  • The caller contract is unchanged: the same query string returns the same response and OpenAPI still lists the parameters flat.
  • Names in the grouped version come from the record properties, so they appear PascalCase; query binding stays case-insensitive.
  • The author recommends it past roughly four query parameters or when two endpoints share the same filter shape.
  • The cost: readers must open a separate type to see what the endpoint accepts.

Adding a sort direction to a product search endpoint pushed the handler to six loose parameters, with an injected `ProductCatalog` buried among the query values and a `Query(...)` call aligned by counting commas. The author moves those values into a `record struct` with `[FromQuery]` properties and accepts it via `[AsParameters]`, leaving two arguments: the request model and the dependency.

Both endpoints returned byte-identical responses for the same query string, and the generated OpenAPI document still lists all six parameters flat in the query, so client generators see no difference. Only casing changes, since names come from the record properties; binding stays case-insensitive. The author reaches for it past roughly four parameters, at the cost of a separate type to open.

Real-world use

  • Product search, listing or reporting endpoints where filtering, sorting and paging parameters keep accumulating
  • Two endpoints that share the same filter shape, such as product and order searches, fed by one type
  • Handlers where injected services and request values are mixed and a swapped argument would silently return the wrong page

Why it matters

It is a readability refactor rather than a behavior change: signatures get shorter and silent mistakes from misordered arguments become less likely, while clients see nothing different.

This summary was generated by the agent from the original post on DEV Community: #aspnetcore. The full text and all rights belong to its author and publisher. Go to original

Related stories

Feedback

Found a bug or have an idea? Your message lands straight in my inbox.

Type of message