Preserve IOutboundParameterTransformer on optional route constraints#65578
Open
kubaflo wants to merge 1 commit intodotnet:mainfrom
Open
Preserve IOutboundParameterTransformer on optional route constraints#65578kubaflo wants to merge 1 commit intodotnet:mainfrom
kubaflo wants to merge 1 commit intodotnet:mainfrom
Conversation
Contributor
|
Thanks for your PR, @@kubaflo. Someone from the team will get assigned to your PR shortly and we'll get it reviewed. |
Contributor
There was a problem hiding this comment.
Pull request overview
This PR addresses issue #23063 — when a route constraint implements IOutboundParameterTransformer and the route parameter is optional, wrapping the constraint in OptionalRouteConstraint caused the transformer to be silently dropped, resulting in incorrect URL generation.
Changes:
- Introduced
OptionalOutboundParameterTransformerRouteConstraint, an internal class that extendsOptionalRouteConstraintwhile also delegatingTransformOutboundto the inner constraint. - Updated
DefaultParameterPolicyFactory.InitializeRouteConstraintto use the new class when the inner constraint implementsIOutboundParameterTransformer. - Added agentic workflow skill files (
fix-issue,write-tests,verify-tests,try-fix,ai-summary-commentSKILL.md and associated scripts/tests) — unrelated to the routing fix.
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
src/Http/Routing/src/Constraints/OptionalOutboundParameterTransformerRouteConstraint.cs |
New internal class that preserves IOutboundParameterTransformer behavior through optional constraint wrapping |
src/Http/Routing/src/DefaultParameterPolicyFactory.cs |
Selects new wrapper class when inner constraint implements IOutboundParameterTransformer |
src/Http/Routing/test/UnitTests/DefaultParameterPolicyFactoryTest.cs |
Regression test for the bug fix, including a TransformingRouteConstraint helper |
.github/skills/fix-issue/SKILL.md |
Agentic workflow definition (5-phase issue fixer) |
.github/skills/fix-issue/tests/test-skill-definition.sh |
Tests for the fix-issue SKILL.md — several assertions fail against current SKILL.md content |
.github/skills/fix-issue/tests/test-ai-summary-comment.sh |
Tests for the ai-summary-comment scripts — references non-existent post-try-fix-comment.sh |
.github/skills/ai-summary-comment/SKILL.md |
Skill definition for posting PR progress comments |
.github/skills/ai-summary-comment/scripts/post-ai-summary-comment.sh |
Shell script that posts/updates the AI summary comment on a PR |
.github/skills/write-tests/SKILL.md |
Skill definition for writing unit tests |
.github/skills/verify-tests/SKILL.md |
Skill definition for verifying tests |
.github/skills/try-fix/SKILL.md |
Skill definition for attempting alternative fixes |
When a route constraint implements IOutboundParameterTransformer, wrapping it in OptionalRouteConstraint loses the transformer capability because OptionalRouteConstraint does not implement the interface. Add OptionalOutboundParameterTransformerRouteConstraint that extends OptionalRouteConstraint and delegates TransformOutbound to the inner constraint. DefaultParameterPolicyFactory.InitializeRouteConstraint now uses this wrapper when the inner constraint is a transformer. Fixes dotnet#23063 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
d498fe7 to
d0791a2
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
🤖 AI Summary
🔍 Automated Fix Report
🔍 Pre-Flight — Context & Validation
Issue: #23063 —
TransformOutboundnot called for optional route segments with parameter transformersArea:
src/Http/Routing/Root Cause: When a route constraint is marked optional,
DefaultParameterPolicyFactorywraps it inOptionalRouteConstraint, which only implementsIRouteConstraint— losing theIOutboundParameterTransformerinterface. TheTemplateBinderchecks forIOutboundParameterTransformerseparately, so the transformer is never invoked for optional segments.Classification: Bug — interface loss during constraint wrapping
🧪 Test — Bug Reproduction
Test File:
src/Http/Routing/test/UnitTests/Constraints/OptionalOutboundParameterTransformerRouteConstraintTest.csTests Added:
Match_DelegatesToInnerConstraint_WhenValuePresentMatch_ReturnsTrue_WhenValueIsOptionalOrEmptyTransformOutbound_DelegatesToInnerTransformerStrategy: Verified that the new wrapper constraint correctly delegates both
IRouteConstraint.MatchandIOutboundParameterTransformer.TransformOutboundto the inner constraint.🚦 Gate — Test Verification & Regression
Gate Result: ✅ All 21 routing constraint tests pass
Test Command:
Regression: No failures in existing test suite.
🔧 Fix — Analysis & Comparison (✅ 2 passed, ❌ 1 failed)
Fix: Preserve
IOutboundParameterTransformerinterface when wrapping route constraints inOptionalRouteConstraint.OptionalOutboundParameterTransformerRouteConstraintclassDefaultParameterPolicyFactoryInnerConstraintat 3 consumer sites✅ Attempt 0: PASS
Approach: New
OptionalOutboundParameterTransformerRouteConstraintclass extendingOptionalRouteConstraint+ implementingIOutboundParameterTransformer.Created a new internal class that preserves both interfaces. Modified
DefaultParameterPolicyFactory.InitializeRouteConstraintto detectIOutboundParameterTransformerand use the specialized wrapper.📄 Diff
❌ Attempt 1: FAIL
Approach: Private nested
OptionalTransformerConstraintclass insideDefaultParameterPolicyFactory.Instead of a separate file, use a private nested class that implements both
IRouteConstraintandIOutboundParameterTransformer, composingOptionalRouteConstraintinternally. Test fails because it checks concrete typeOptionalOutboundParameterTransformerRouteConstraint— would need test modification.📄 Diff
✅ Attempt 2: PASS
Approach: Unwrap
OptionalRouteConstraint.InnerConstraintat all consumer sites (TemplateBinder, DefaultTemplateBinderFactory, DfaMatcherBuilder).Instead of creating a new wrapper class, check at each site where
IOutboundParameterTransformeris queried whether the policy is anOptionalRouteConstraintwhoseInnerConstraintimplementsIOutboundParameterTransformer, and unwrap it. No new types needed, but touches 3 consumer files.📄 Diff