Skip to content

Fix #2951: drop the regex route constraint from the default Swagger route - #4130

Merged
martincostello merged 2 commits into
domaindrivendev:masterfrom
RaphaelFakhri:fix/2951-route-constraint
Sep 29, 2026
Merged

martincostello merged 2 commits into
domaindrivendev:masterfrom
RaphaelFakhri:fix/2951-route-constraint

Conversation

@RaphaelFakhri

Copy link
Copy Markdown
Contributor

Fixes #2951. This takes up the offer above: "We'd be happy to take a PR that changes the route template ... that doesn't need a Regex."

It still reproduces on master. SwaggerOptions.DefaultRouteTemplate is /swagger/{documentName}/swagger.{extension:regex(^(json|ya?ml)$)}, and SwaggerMiddleware's constructor eagerly resolves a TemplateBinder for it. An application built with CreateSlimBuilder or AddRoutingCore does not register the regex constraint, so a standalone app against master throws at startup with the exception in the report, from SwaggerMiddleware..ctor.

The default template drops the constraint, and the middleware applies the equivalent allow-list in code, but only when the extension parameter has no inline constraint of its own. A custom template that brings its own constraints keeps going through the TemplateBinder path unchanged. The allow-list is json, yaml, yml, compared with OrdinalIgnoreCase, matching the case-insensitivity of the regex it replaces.

MapSwagger's default parameter value changes with it, so PublicAPI.Unshipped.txt carries the *REMOVED* and replacement pair the analyzers require.

This also deletes the repo's own workaround: test/WebSites/WebApi.Aot/Program.cs was registering SetParameterPolicy<RegexInlineRouteConstraint> to get around exactly this, so the in-repo AoT slim-builder site now exercises the fix rather than papering over it.

SwaggerMiddlewareRouteTemplateTests covers building the pipeline under AddRoutingCore() with no regex constraint registered, plus eight route cases: .json, .yaml, .yml, .JSON and .YAML serve 200, and .txt, .html and .jsonx fall through to a 404. All nine fail against master's source with the same RouteCreationException from the report. With the change, Swashbuckle.AspNetCore.SwaggerGen.Test is 769 passed, 0 failed on net8.0. I also confirmed the standalone slim-builder app end to end: it crashed before, and after the change it starts, serves a valid document at swagger.json, serves swagger.yaml as text/yaml, and 404s swagger.txt.

Two things I did not change, deliberately. .YAML returns 200 with JSON content, because the old regex was case-insensitive while the json/yaml switch downstream is case-sensitive; that is master's existing behaviour and this PR is not the place to change it. And a user with a custom, unconstrained {extension} template, say docs/{documentName}/spec.{extension}, previously got JSON for any extension and now sees anything outside the allow-list fall through to the next middleware. That is the same tightening #2418 intended for the default template, but it is a behaviour change and worth your call.

@codecov

codecov Bot commented Aug 25, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 95.32%. Comparing base (d0b1e26) to head (1af6de0).
⚠️ Report is 3 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #4130      +/-   ##
==========================================
+ Coverage   95.24%   95.32%   +0.08%     
==========================================
  Files         111      111              
  Lines        4142     4149       +7     
  Branches      848      850       +2     
==========================================
+ Hits         3945     3955      +10     
+ Misses        197      194       -3     
Flag Coverage Δ
Linux 95.32% <100.00%> (+0.08%) ⬆️
Windows 95.32% <100.00%> (+0.08%) ⬆️
macOS 95.32% <100.00%> (+0.08%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

…fault Swagger route

SwaggerMiddleware resolves a TemplateBinder for SwaggerOptions.RouteTemplate in
its constructor, and the default template constrained {extension} with an inline
regex. An application built with CreateSlimBuilder or AddRoutingCore does not
register that constraint, so the middleware threw at startup.

The default template no longer uses a constraint, and the middleware applies the
same json, yaml and yml allow-list in code when the extension parameter carries
no constraint of its own. Custom templates that bring their own constraints are
unaffected.
@RaphaelFakhri

Copy link
Copy Markdown
Contributor Author

Both suggestions are applied: the test is renamed to UseSwagger_Works_With_AddRoutingCore, and the explanatory comment in it is removed, since the new name says what the test covers.

On the PublicAPI.Unshipped.txt note: agreed, only the default value of the pattern parameter changes. The extension check that the regex performed now runs in the middleware for the default template, and custom templates that specify their own constraints behave as before.

@RaphaelFakhri
RaphaelFakhri force-pushed the fix/2951-route-constraint branch from 18fdfb2 to 1af6de0 Compare September 29, 2026 10:14
@martincostello martincostello added this to the v10.2.4 milestone Sep 29, 2026
@martincostello
martincostello merged commit 62de69c into domaindrivendev:master Sep 29, 2026
14 checks passed
@github-actions

github-actions Bot commented Oct 7, 2026

Copy link
Copy Markdown
Contributor

Thanks for your contribution @RaphaelFakhri - the changes from this pull request have been published as part of version 10.3.0 📦, which is now available from NuGet.org 🚀

This was referenced Oct 7, 2026
This was referenced Oct 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Breaking change in 6.6.1; It now requires you to have the Regex Route Constraint even if you don't use it

2 participants