Skip to content

Fix #18539 - add Blazor catch-all route parameter #24038

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jul 18, 2020

Conversation

zbecknell
Copy link
Contributor

Summary of the changes

Addresses #18539.

Hopefully this is a useful start, @captainsafia!

@zbecknell zbecknell requested review from SteveSandersonMS and a team as code owners July 16, 2020 23:57
@ghost ghost added the area-blazor Includes: Blazor, Razor Components label Jul 16, 2020
@mkArtakMSFT mkArtakMSFT added the community-contribution Indicates that the PR has been added by a community member label Jul 17, 2020
Copy link
Member

@javiercn javiercn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall looks great!

Maybe it would be good to add a couple of E2E tests to validate the encoding bit here

This commit can be used as a reference on what to change to add an E2E test for it

Copy link
Member

@javiercn javiercn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for adding the E2E tests!

This looks great!

I'll merge once the build passes. Thanks again @zbecknell for the contribution!

@zbecknell
Copy link
Contributor Author

Hopefully those will pass @javiercn, I get this message at the end of running tests on my Mac:

Selenium tests are not supported for OS 'Unix' and architecture 'x64'.

@javiercn
Copy link
Member

@zbecknell Yep, we haven't gotten around to enable selenium cross-plat. The setup is quite painful to do, so we mostly run on Windows/chromium

[Fact]
public void CanArriveAtPageWithCatchAllParameterWithoutEscapedSlashes()
{
SetUrlViaPushState("/WithCatchAllParameterWithoutEscapedSlashes/life/the/universe/and/everything = 42");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this here might need to be in escaped syntax so that we can see the difference. I think that's why the tests are failing. On this one you should see the unescaped value, on the one above you should see the same value.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, ok, I did notice another call to SetUrlViaPushState had encoded values. I'll get that changed.

@zbecknell
Copy link
Contributor Author

Ok, pretty easy to see what's happening. I guess my first question should've been: do we expect the full value to be encoded? I didn't catch any tests that show this yet, but I may've missed them.

Current behavior:

{*catchAllWithEncodedSlashes} <- encodes slashes but not anything else
{**catchAllWithoutEncodedSlashes} <- doesn't encode anything

What is our desired behavior?

@javiercn
Copy link
Member

Ok, pretty easy to see what's happening. I guess my first question should've been: do we expect the full value to be encoded? I didn't catch any tests that show this yet, but I may've missed them.

Current behavior:

{*catchAllWithEncodedSlashes} <- encodes slashes but not anything else
{**catchAllWithoutEncodedSlashes} <- doesn't encode anything

What is our desired behavior?

It's not about encoding, it's about decoding. If the url has encoded segments on it, using ** allows you to capture the URL without decoding, which allows you to "round-trip". If you use * the segments get decoded, which means that if you use that for a link, the new link will not be escaped (doesn't roundtrip). Does that make sense?

else
{
catchAllValue = string.Join('/', context.Segments[Range.StartAt(Template.Segments.Length - 1)]);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I realized now that I overlooked this. We should be using Uri.UnescapeDataString here. It is likely that the previous behavior for * was to not do anything, which should have not been the case, as that's the behavior ** has on ASP.NET Core routing.

I think I need to think about this a bit more, and chat with some other folks on the team, since this is a small breaking change, and I just want to make sure we are ok with it before we take it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think previously * would be completely rejected in a template, right? So for Blazor routing we aren't introducing a breaking change, to my knowledge. I do understand the problem now, I seem to have had it backward in my head, so I can at least start by updating to unescape these segments while you double-check with the team.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's true, I had a brainfreeze :). So no breaking change, we should just make sure the behavior matches the one in ASP.NET Core routing, which is * decodes the url, and ** does not

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, * and ** I believe are used for link generation, which might not apply here. Give me a second to confirm, it's been a while since I've looked at this specifically.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doh, ** is used for link generation... so I've really mangled my interpretation of what needs to happen here. In this case, I can just decode the entire catch-all value when it's incoming. And I don't really need to look for ** but just * presumably.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like I can simplify this by not worrying about **. Also the RouteContext already decodes the values when adding the context segments so I believe that is taken care of as well.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes sense. Lets just do * for now. We can always add ** back if we have to

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Final question: do we want to throw if a template starts with more than one *?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that way we make sure we can add it in the future without breaking anyone

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! That's what I thought, just wanted to confirm.

@zbecknell
Copy link
Contributor Author

Cleaned up now. Fingers crossed for E2E tests.

Copy link
Member

@captainsafia captainsafia left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, @zbecknell! This looks great.

@sfmskywalker
Copy link
Contributor

sfmskywalker commented Aug 30, 2020

I'd like to take advantage of this new feature, and assumed that it would be built as part of the nightly build feed at https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet5/nuget/v3/index.json. However, when I try I get the following exception: InvalidOperationException: Invalid template 'categories/{*slug}'. The character '*' in parameter segment '{*slug}' is not allowed.

I referenced Microsoft.AspNetCore.Components* version 5.0.0-rc.1.20429.8

@captainsafia
Copy link
Member

@sfmskywalker Can you open an issue with a reproduction?

@zbecknell
Copy link
Contributor Author

I'm able to get this working when updating to the latest nightly rc1 of both the SDK and NuGet packages @sfmskywalker.

Annotation 2020-09-01 092839

(Ignore that Preview8Repro title, just reused an existing project.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-blazor Includes: Blazor, Razor Components community-contribution Indicates that the PR has been added by a community member
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants