Skip to content

fix(http): honor the Name on [FromRoute] for endpoint method parameters#3356

Merged
jeremydmiller merged 2 commits into
JasperFx:mainfrom
outofrange-consulting:fix/fromroute-named-route-parameter
Jul 10, 2026
Merged

fix(http): honor the Name on [FromRoute] for endpoint method parameters#3356
jeremydmiller merged 2 commits into
JasperFx:mainfrom
outofrange-consulting:fix/fromroute-named-route-parameter

Conversation

@outofrange-consulting

Copy link
Copy Markdown
Contributor

Problem

[FromRoute(Name = "...")] is only read inside AsParametersBindingFrame. On a plain endpoint method parameter the attribute's Name is ignored — RouteParameterStrategy matches on ParameterInfo.Name only:

var matchingRouteParameter = RoutePattern!.Parameters.FirstOrDefault(x => x.Name == parameter.Name);

So for /journeys/{journey-id}/legs + [FromRoute(Name = "journey-id")] int journeyId:

  • RouteParameterStrategy misses ("journeyId" != "journey-id")
  • matching falls through the strategy list to QueryStringParameterStrategy, which claims any parseable type
  • the generated handler reads httpContext.Request.Query["journeyId"], so the argument binds to 0

Silent wrong binding, no exception. And a kebab-cased route token can't be bound by convention at all, because journey-id isn't a legal C# identifier — so the attribute was the only way to reach it.

Fix

RouteParameterStrategy.TryMatch now resolves the route argument by the attribute's Name when one is supplied, and throws when no such route argument exists rather than letting the parameter be quietly bound from somewhere else — mirroring the existing [AsParameters] behaviour.

Two related lookups matched route variables on Variable.Usage (the sanitized C# identifier, journey_id) instead of HttpElementVariable.Name (the route key, journey-id):

  • HttpChain.FindRouteVariable(Type, string) — the de-dupe check never hit for a sanitized name, so two members bound to the same route token emitted the same local twice (CS0128).
  • HttpChain.buildParameterDescription — the OpenAPI parameter lost its real type and fell back to string unless the route carried an inline constraint.

Both now compare against the route key.

Tests

named_route_parameter_binding covers a kebab-cased route token bound to an int method parameter, to a string method parameter, and through [AsParameters] alongside a [FromBody] member. The two direct-parameter cases fail on main; all three pass with the fix.

Full Wolverine.Http.Tests green (811 passed, 10 skipped), and dotnet build wolverine.slnx -c Release succeeds.

Repro

The second commit adds repro/kebab-cased-route-parameter.cs, a .NET 10 file-based app that boots a real Wolverine HTTP host, exercises both shapes over HTTP, and exits non-zero on failure. It's self-contained (dotnet run repro/kebab-cased-route-parameter.cs) and needs no test framework.

With the fix:

PASS  GET /journeys/42/legs -> "42"
PASS  POST /journeys/7/passengers -> "7:Maverick"

Against main:

FAIL  GET /journeys/42/legs -> expected "42", got "0"
PASS  POST /journeys/7/passengers -> "7:Maverick"

Happy to drop that commit if a top-level repro/ directory isn't a convention you want — the fix and the xUnit coverage stand on their own without it.

Geoffrey MARC added 2 commits July 10, 2026 17:39
[FromRoute(Name = "my-id")] was only read by AsParametersBindingFrame. On a
plain endpoint method parameter the attribute name was ignored: matching fell
through to the parameter name, missed the route token, and QueryStringParameterStrategy
silently bound the argument from the query string instead. A kebab-cased route
token could not be bound at all, since it is not a legal C# identifier.

RouteParameterStrategy now resolves the route argument by the attribute name when
one is given, and throws when no such route argument exists rather than binding
from somewhere else.

Route variables are also now looked up by their route key rather than by their
sanitized C# usage, so a route token containing '-', '.' or '/' de-duplicates
correctly and carries its real type onto the generated OpenAPI parameter.
@jeremydmiller
jeremydmiller merged commit 2736bb0 into JasperFx:main Jul 10, 2026
25 checks passed
This was referenced Jul 10, 2026
This was referenced Jul 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants