From 879a0d58cc364bf811dfa36ff2ee5400cb2e97b3 Mon Sep 17 00:00:00 2001 From: Jason Rebelo Neves Date: Fri, 1 Apr 2022 01:32:59 +0200 Subject: [PATCH 1/3] Add 'IgnoreQueryString' parameter This commit adds the `IgnoreQueryString` parameter, allowing the user to have routes match their URLs regardless of whether query parameters are set or not. Co-authored-by: James Yeung Co-authored-by: Safia Abdalla --- src/Components/Web/src/PublicAPI.Unshipped.txt | 2 ++ src/Components/Web/src/Routing/NavLink.cs | 15 +++++++++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/Components/Web/src/PublicAPI.Unshipped.txt b/src/Components/Web/src/PublicAPI.Unshipped.txt index 34c8afc7fb6e..21248b15c88b 100644 --- a/src/Components/Web/src/PublicAPI.Unshipped.txt +++ b/src/Components/Web/src/PublicAPI.Unshipped.txt @@ -1,3 +1,5 @@ #nullable enable Microsoft.AspNetCore.Components.Forms.InputRadio.Element.get -> Microsoft.AspNetCore.Components.ElementReference? Microsoft.AspNetCore.Components.Forms.InputRadio.Element.set -> void +Microsoft.AspNetCore.Components.Routing.NavLink.IgnoreQueryString.get -> bool +Microsoft.AspNetCore.Components.Routing.NavLink.IgnoreQueryString.set -> void diff --git a/src/Components/Web/src/Routing/NavLink.cs b/src/Components/Web/src/Routing/NavLink.cs index 3e2d96c81efb..3c3431fd5eef 100644 --- a/src/Components/Web/src/Routing/NavLink.cs +++ b/src/Components/Web/src/Routing/NavLink.cs @@ -44,6 +44,12 @@ public class NavLink : ComponentBase, IDisposable [Parameter] public RenderFragment? ChildContent { get; set; } + /// + /// Gets or sets a flag to indicate whether route matching should ignore the query string. + /// + [Parameter] + public bool IgnoreQueryString { get; set; } + /// /// Gets or sets a value representing the URL matching behavior. /// @@ -113,13 +119,15 @@ private bool ShouldMatch(string currentUriAbsolute) return false; } - if (EqualsHrefExactlyOrIfTrailingSlashAdded(currentUriAbsolute)) + var matchingUri = IgnoreQueryString ? RemoveQueryString(currentUriAbsolute) : currentUriAbsolute; + + if (EqualsHrefExactlyOrIfTrailingSlashAdded(matchingUri)) { return true; } if (Match == NavLinkMatch.Prefix - && IsStrictlyPrefixWithSeparator(currentUriAbsolute, _hrefAbsolute)) + && IsStrictlyPrefixWithSeparator(matchingUri, _hrefAbsolute)) { return true; } @@ -192,4 +200,7 @@ private static bool IsStrictlyPrefixWithSeparator(string value, string prefix) return false; } } + + private static string RemoveQueryString(string path) + => path.Contains('?') ? path.Split('?')[0] : path; } From 9682520c555860e6461f5f5aefa6d54691b08bb7 Mon Sep 17 00:00:00 2001 From: Jason Rebelo Neves Date: Fri, 1 Apr 2022 04:50:02 +0200 Subject: [PATCH 2/3] Handle trailing slashes with query parameters If a route includes trailing slashes and query parameters, given `Match` is set to `NavLinkMatch.All` and `IgnoreQueryString` is set to `true`, the base route (without trailing slash and query string) should be matched. --- src/Components/Web/src/Routing/NavLink.cs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/Components/Web/src/Routing/NavLink.cs b/src/Components/Web/src/Routing/NavLink.cs index 3c3431fd5eef..1be2d02baf2a 100644 --- a/src/Components/Web/src/Routing/NavLink.cs +++ b/src/Components/Web/src/Routing/NavLink.cs @@ -202,5 +202,18 @@ private static bool IsStrictlyPrefixWithSeparator(string value, string prefix) } private static string RemoveQueryString(string path) - => path.Contains('?') ? path.Split('?')[0] : path; + { + if (!path.Contains('?')) + { + return path; + } + + var pathWithoutQuery = path.Split('?')[0]; + + // We remove trailing slashes to ensure the following matches: + // - "/abc/?value=123" matches "/abc" + // - "/abc/def?value=123" matches "/abc/def" + // - "/abc/def/?value=123" matches "/abc/def" + return pathWithoutQuery.EndsWith('/') ? pathWithoutQuery.TrimEnd('/') : pathWithoutQuery; + } } From 22ab5022a7ba5b73b89056e329610bc30f4a0ceb Mon Sep 17 00:00:00 2001 From: Jason Rebelo Neves Date: Fri, 1 Apr 2022 04:52:31 +0200 Subject: [PATCH 3/3] Add E2E tests --- .../test/E2ETest/Tests/RoutingTest.cs | 40 +++++++++++++++++++ .../BasicTestApp/RouterTest/Links.razor | 6 +++ 2 files changed, 46 insertions(+) diff --git a/src/Components/test/E2ETest/Tests/RoutingTest.cs b/src/Components/test/E2ETest/Tests/RoutingTest.cs index 778ecd155104..201817b3b29c 100644 --- a/src/Components/test/E2ETest/Tests/RoutingTest.cs +++ b/src/Components/test/E2ETest/Tests/RoutingTest.cs @@ -880,6 +880,46 @@ public void CanNavigateBetweenPagesWithQueryStrings() AssertHighlightedLinks("With query parameters (none)", "With query parameters (passing string value)"); } + [Fact] + public void IgnoresQueryString() + { + SetUrlViaPushState("/WithQueryParameters/IgnoreQueryString?intvalue=123"); + + var app = Browser.MountTestComponent(); + Assert.Equal("123", app.FindElement(By.Id("value-QueryInt")).Text); + AssertHighlightedLinks("Base IgnoreQueryString URL"); + } + + [Fact] + public void IgnoresQueryStringWithTrailingSlash() + { + SetUrlViaPushState("/WithQueryParameters/IgnoreQueryString/?intvalue=123"); + + var app = Browser.MountTestComponent(); + Assert.Equal("123", app.FindElement(By.Id("value-QueryInt")).Text); + AssertHighlightedLinks("Base IgnoreQueryString URL"); + } + + [Fact] + public void DoesNotIgnoreQueryString() + { + SetUrlViaPushState("/WithQueryParameters/DoNotIgnoreQueryString?intvalue=123"); + + var app = Browser.MountTestComponent(); + Assert.Equal("123", app.FindElement(By.Id("value-QueryInt")).Text); + AssertHighlightedLinks("With query parameters (matches all and does not ignore query string)"); + } + + [Fact] + public void DoesNotIgnoreQueryStringWithTrailingSlash() + { + SetUrlViaPushState("/WithQueryParameters/DoNotIgnoreQueryString/?intvalue=123"); + + var app = Browser.MountTestComponent(); + Assert.Equal("123", app.FindElement(By.Id("value-QueryInt")).Text); + AssertHighlightedLinks("With query parameters (matches all and does not ignore query string with trailing slash)"); + } + private long BrowserScrollY { get => (long)((IJavaScriptExecutor)Browser).ExecuteScript("return window.scrollY"); diff --git a/src/Components/test/testassets/BasicTestApp/RouterTest/Links.razor b/src/Components/test/testassets/BasicTestApp/RouterTest/Links.razor index 67d6bb8a2474..fb6ef88e186c 100644 --- a/src/Components/test/testassets/BasicTestApp/RouterTest/Links.razor +++ b/src/Components/test/testassets/BasicTestApp/RouterTest/Links.razor @@ -30,6 +30,12 @@
  • Download Me
  • Null href never matches
  • +
  • Base IgnoreQueryString URL
  • +
  • With query parameters (matches all and ignores query string)
  • +
  • With query parameters (matches all and ignores query string with trailing slash)
  • +
  • Base DoNotIgnoreQueryString URL
  • +
  • With query parameters (matches all and does not ignore query string)
  • +
  • With query parameters (matches all and does not ignore query string with trailing slash)