Skip to content

GH-5099 Wolverine.HTTP: an omitted query, header or form value binds the parameter's declared default - #5101

Merged
jeremydmiller merged 1 commit into
mainfrom
gh-5099-query-default-values
Oct 20, 2026
Merged

jeremydmiller merged 1 commit into
mainfrom
gh-5099-query-default-values

Conversation

@jeremydmiller

Copy link
Copy Markdown
Member

Problem

A Wolverine.HTTP parameter bound from the query string ignored its declared C# default when the request omitted the value. int limit = 100 bound 0 and string name = "all" bound null. The generated code initialized the variable to default, and nothing read ParameterInfo.DefaultValue. ASP.NET Core Minimal APIs bind the declared default. CritterWatch's audit-log endpoint returned [] for every request without ?limit because of this.

Fix

  • ReadHttpFrame takes the declared default of the parameter it binds and emits it as a C# literal through the new DeclaredDefaultValue helper. It escapes strings and chars, adds numeric suffixes, and casts enums from their underlying number.
  • A parsed value with a declared default now parses into a temporary, as a nullable value already did. A failed TryParse writes the type's default into its out argument, and bool and enum parsing run even on a missing value. Parsing straight into the variable would wipe out the default.
  • A string value becomes (string?)raw ?? "default".
  • The default applies wherever a method parameter binds:
    • the query string, including [FromQuery(Name = ...)]
    • the form
    • headers, including postprocessor headers
    • optional route values
    • [AsParameters] constructor parameters
  • The OpenAPI description now carries the default on query and form parameters.
  • In lenient mode, a value that is present but unparseable now keeps the declared default instead of the type default. Strict mode still returns 400.

Tests

New declared_default_values_5099 in Wolverine.Http.Tests, with endpoints in WolverineWebApi:

  • Defaults for int, string, bool, enum, double, negative short and int?.
  • An explicit value still wins, and an unparseable value keeps the default.
  • A renamed query key, an escaped string literal, headers, form values and [AsParameters].
  • The OpenAPI default and the literal helper.

Results:

  • 7 of the new integration tests fail when the default is not applied.
  • The full Wolverine.Http.Tests suite passes on net10.0: 1307 passed, 10 skipped, 0 failed.
  • dotnet build wolverine.slnx -c Release -f net9.0 has 0 errors.

F# code generation is unchanged.

Closes #5099

🤖 Generated with Claude Code

https://claude.ai/code/session_01DCggXgxnG3EBXoR9rrq37U

…the parameter's declared default

`int limit = 100` bound 0 and `string name = "all"` bound null when the request omitted the value,
because the generated code initialized the variable to `default` and never read
ParameterInfo.DefaultValue. ASP.NET Core Minimal APIs bind the declared default.

- ReadHttpFrame takes the declared default of the parameter it binds and emits it as a C# literal
  (DeclaredDefaultValue: strings and chars escaped, numeric suffixes, enums cast from their number).
- A parsed value with a declared default parses into a temporary, like a nullable already did. A
  failed TryParse writes the type default into its out argument, and bool/enum parsing runs even on a
  missing value, so parsing straight into the variable would clobber the default.
- A string value becomes `(string?)raw ?? "default"`.
- Applied wherever a method parameter binds: query string, form, header (including postprocessor
  headers), optional route values, and [AsParameters] constructor parameters.
- The OpenAPI description carries the default on query and form parameters.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DCggXgxnG3EBXoR9rrq37U
@jeremydmiller
jeremydmiller merged commit 5a1a09a into main Oct 20, 2026
47 checks passed
This was referenced Oct 21, 2026
This was referenced Oct 26, 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.

Wolverine.HTTP: a query parameter's C# default value is ignored when the query string omits it (int limit = 100 binds 0)

1 participant