Follow-up from #2174 (v13.0.0).
Is your feature request related to a problem?
#2174 made path/route-template parameters generate inline (reflection-free). Query parameters still fall back to the reflection request builder:
- auto-appended query params:
[Get("/users")] Task<T> Search(string q) -> /users?q=...
[Query] (including [Query(Format=...)], nested/collection expansion, custom delimiters)
[AliasAs] on a query parameter
A method with any of these is emitted against BuildRestResultFuncForMethod (the reflection tail), so it throws at runtime under AddRefitGeneratedClient (generated-only) or NativeAOT. Query params are the most common Refit shape, so the generated-only/AOT path is still unusable for typical query APIs. The runtime symptom is #2185.
Describe the solution you'd like
Generate inline request building for methods whose only otherwise-unsupported parameters are query params. The generated query string must match the reflection path's escaping and formatting so the RequestUri is identical between the two.
Describe alternatives you've considered
Describe suggestions on how to achieve the feature
Generator (src/InterfaceStubGenerator.Shared/):
Parser.Request.cs: ParseRequestParameter returns UnsupportedRequestParameter (~line 357) for a parameter with no {...} placeholder. Add a RequestParameterKind.Query, classify plain / [Query] / [AliasAs] params into it, and relax canGenerateInline in ParseRequest.
- Reuse the existing
[Query] parsing (ParseQueryAttribute*, ~lines 580-625) and IsSimpleType (Parser.Request.Helpers.cs).
Runtime (src/Refit/):
- Add a query-append helper modeled on
GeneratedRequestRunner.BuildRequestPath: linear scan, ValueStringBuilder, StringHelpers.EscapeDataString per value, handling collection expansion and delimiters. The reflection version is in RequestBuilderImplementation.RequestBuilding.cs.
Guardrails:
- Value formatting still goes through
IUrlParameterFormatter; keep that boundary, the separate value-formatting issue covers it.
- Keep the RF006 fallback analyzer and
GeneratedRequestBuildingFallbackContractTests in sync: as these shapes become inline, their expectedFallback cases flip.
Tests: emit-load-invoke asserting the final RequestUri (single param, multiple, [AliasAs], [Query(Format=...)], collection, null/empty, and a value that needs escaping such as "a b/c") plus Verify snapshots.
Additional context
Deferred from the #2174 review. Related: #2185, #2168, #2169, #2182. Dotted ({request.Prop}) and round-trip ({**param}) placeholders stay on the reflection fallback (#2046) and are already covered by tests.
Follow-up from #2174 (v13.0.0).
Is your feature request related to a problem?
#2174 made path/route-template parameters generate inline (reflection-free). Query parameters still fall back to the reflection request builder:
[Get("/users")] Task<T> Search(string q)->/users?q=...[Query](including[Query(Format=...)], nested/collection expansion, custom delimiters)[AliasAs]on a query parameterA method with any of these is emitted against
BuildRestResultFuncForMethod(the reflection tail), so it throws at runtime underAddRefitGeneratedClient(generated-only) or NativeAOT. Query params are the most common Refit shape, so the generated-only/AOT path is still unusable for typical query APIs. The runtime symptom is #2185.Describe the solution you'd like
Generate inline request building for methods whose only otherwise-unsupported parameters are query params. The generated query string must match the reflection path's escaping and formatting so the
RequestUriis identical between the two.Describe alternatives you've considered
RouteFragmentModelunion (constant / standard-param / object-access / round-trip), a useful reference for this and the dotted/round-trip work.Describe suggestions on how to achieve the feature
Generator (
src/InterfaceStubGenerator.Shared/):Parser.Request.cs:ParseRequestParameterreturnsUnsupportedRequestParameter(~line 357) for a parameter with no{...}placeholder. Add aRequestParameterKind.Query, classify plain /[Query]/[AliasAs]params into it, and relaxcanGenerateInlineinParseRequest.[Query]parsing (ParseQueryAttribute*, ~lines 580-625) andIsSimpleType(Parser.Request.Helpers.cs).Runtime (
src/Refit/):GeneratedRequestRunner.BuildRequestPath: linear scan,ValueStringBuilder,StringHelpers.EscapeDataStringper value, handling collection expansion and delimiters. The reflection version is inRequestBuilderImplementation.RequestBuilding.cs.Guardrails:
IUrlParameterFormatter; keep that boundary, the separate value-formatting issue covers it.GeneratedRequestBuildingFallbackContractTestsin sync: as these shapes become inline, theirexpectedFallbackcases flip.Tests: emit-load-invoke asserting the final
RequestUri(single param, multiple,[AliasAs],[Query(Format=...)], collection, null/empty, and a value that needs escaping such as"a b/c") plus Verify snapshots.Additional context
Deferred from the #2174 review. Related: #2185, #2168, #2169, #2182. Dotted (
{request.Prop}) and round-trip ({**param}) placeholders stay on the reflection fallback (#2046) and are already covered by tests.