Skip to content

Allow special characters in Wolverine.HTTP route templates (fixes #3282)#3297

Merged
jeremydmiller merged 1 commit into
mainfrom
fix/http-route-special-chars-3282
Jul 5, 2026
Merged

Allow special characters in Wolverine.HTTP route templates (fixes #3282)#3297
jeremydmiller merged 1 commit into
mainfrom
fix/http-route-special-chars-3282

Conversation

@jeremydmiller

Copy link
Copy Markdown
Member

Fixes #3282.

Problem

Wolverine derives the generated handler C# type name from an endpoint's route template. A route can legally contain characters that are valid in a URL path but not in a C# identifier — most notably $ in an RPC-style route like /assets/$action. The name-derivation only stripped Path.GetInvalidPathChars() (a filesystem concept), so $ survived into assembly.AddType(...) and codegen failed:

CS1056: Unexpected character '$'

Fix (A + B + disambiguator)

A — Sanitize to a valid C# identifier. In HttpChain.Codegen.determineFileName, any character that isn't a valid identifier char (letter/digit/_) becomes _, underscore runs are collapsed, and a leading digit is prefixed with _. Routes with special characters now just work — no user action needed.

B — TypeName escape hatch. All [WolverineVerb] attributes gain an optional TypeName property to set the generated type name explicitly for edge cases. The override is itself sanitized, so it can never smuggle invalid code into codegen.

[WolverinePut("/assets/$action", TypeName = "TriggerAssetAction")]
public static string TriggerAction() => "triggered";

Collision disambiguator (built in from the start). Two routes that sanitize to the same type name (e.g. /a$b and /a-ba_b) now receive a short, deterministic FNV-1a suffix in HttpGraph, applied only to chains that actually collide. Determinism matters for TypeLoadMode.Static, where codegen-time names must match what was written to disk.

Tests (special_characters_in_route_templates.cs)

  • Reproduce the original CS1056 (route + real codegen via InitializeSynchronously) — now passes.
  • The generated type name is a valid C# identifier.
  • TypeName override is used, and is still sanitized.
  • Colliding routes get distinct names and both compile.
  • The disambiguation suffix is deterministic across graph builds.

Docs

New "Special Characters in Routes" section in guide/http/routing.md covering the automatic sanitization and the TypeName escape hatch.

Verification

Full Wolverine.Http.Tests: 802 passed / 0 failed / 10 skipped — no regressions (normal routes derive the same names as before; sanitization is a superset of the old replacements). Release build clean.

🤖 Generated with Claude Code

Wolverine derives the generated handler *type name* from an endpoint's route template, but only
stripped Path.GetInvalidPathChars() when doing so. Characters that are legal in a URL path but not in
a C# identifier — most notably '$' in a route like "/assets/$action" — survived into the generated
type name and made codegen fail with CS1056 "Unexpected character '$'".

Fixes:
- Sanitize the generated type name to a valid C# identifier: any non letter/digit/underscore char
  becomes '_', collapsed underscore runs, and a leading digit is prefixed with '_'. Route templates
  with special characters now "just work".
- Collision handling: two routes that sanitize to the same type name (e.g. "/a$b" and "/a-b" -> "a_b")
  get a short, deterministic FNV-1a suffix in HttpGraph so codegen stays valid. The suffix is stable
  across builds, which matters for TypeLoadMode.Static.
- Escape hatch: WolverineHttpMethodAttribute (all [WolverineVerb] attributes) gains an optional
  TypeName property to set the generated type name explicitly for edge cases. The override is itself
  sanitized so it can never produce invalid code.

Docs: new "Special Characters in Routes" section in guide/http/routing.md covering the automatic
sanitization and the TypeName escape hatch.

Tests: reproduce the CS1056 failure (route + real codegen), the TypeName override (used + sanitized),
collision disambiguation (distinct names, both compile), and determinism of the suffix.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@jeremydmiller
jeremydmiller merged commit c8abcd9 into main Jul 5, 2026
47 of 48 checks passed
This was referenced Jul 9, 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.

Allow special characters in WolverineFx.Http route templates

1 participant