Skip to content

[BlazorWebView] Fixed Allow force reload for URLs with dots in query parameters - #29560

Merged
kubaflo merged 11 commits into
dotnet:inflight/currentfrom
tw4:fix-25689
Jun 21, 2026
Merged

[BlazorWebView] Fixed Allow force reload for URLs with dots in query parameters#29560
kubaflo merged 11 commits into
dotnet:inflight/currentfrom
tw4:fix-25689

Conversation

@tw4

@tw4 tw4 commented May 16, 2025

Copy link
Copy Markdown

Note

Are you waiting for the changes in this PR to be merged?
It would be very helpful if you could test the resulting artifacts from this PR and let us know in a comment if this change resolves your issue. Thank you!

Description of Change

This PR fixes a bug in BlazorWebView where URLs containing dots (.) in query parameters (e.g., ?weight=62.5) could not be force reloaded. The issue was caused by using Path.HasExtension(uriString), which mistakenly treated dots in query strings as if they were part of a file extension.


❌ Before

The original logic:

if (Path.HasExtension(uriString))
    return false;

This evaluates the entire URI string — including query parameters — which incorrectly caused ?value=62.5 to be treated as a file reference, breaking reload behavior.


✅ After

This PR introduces a safer and more accurate approach:

if (Path.HasExtension(uri.AbsolutePath))
    return false;

Along with additional improvements:

  • Validates input with string.IsNullOrWhiteSpace
  • Uses Uri.TryCreate with UriKind.Absolute to safely parse the input and reject relative or malformed URIs
  • Scheme/host matching is preserved through Uri.IsBaseOf, so URIs whose scheme or host does not match the configured base URI are still rejected as before

This ensures that only the actual path is evaluated for file extensions, allowing query strings to contain dots without affecting navigation or reload logic.


Issues Fixed

Fixes #25689

Cover test result
Screenshot 2025-05-16 at 22 54 41


Note: @mattleibow
The previous PR might have been truly cursed 😅 — I created a new branch, rewrote the unit test project from scratch, and everything worked like a charm this time.
No issues so far, and I'm optimistic GitHub Actions will behave too! 🧙‍♂️✨

Also, big thanks to @mattleibow for the support and guidance — your insights helped me see things more clearly! 🙏

Copilot AI review requested due to automatic review settings May 16, 2025 20:01
@tw4
tw4 requested review from a team as code owners May 16, 2025 20:01
@tw4
tw4 requested review from jfversluis and jsuarezruiz May 16, 2025 20:01

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull Request Overview

This PR fixes a bug in BlazorWebView where dots in query parameters incorrectly trigger a file extension check, preventing force reloads. Key changes include using Uri.AbsolutePath for file extension validation, adding input validation for the URL, and restricting allowed schemes.

Reviewed Changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated no comments.

Show a summary per file
File Description
src/BlazorWebView/tests/MauiBlazorWebView.UnitTests/MauiBlazorWebView.UnitTests.csproj New test project setup for unit tests
src/BlazorWebView/tests/MauiBlazorWebView.UnitTests/Extensions_Tests.cs Comprehensive unit tests for URI handling improvements
src/BlazorWebView/src/Maui/Properties/AssemblyInfo.cs Added InternalsVisibleTo attribute for test project visibility
src/BlazorWebView/src/Maui/Extensions/UriExtensions.cs Updated extension method to check for file extensions only on the URI’s AbsolutePath
MauiBlazorWebView.sln Updated solution to include the new test project
Comments suppressed due to low confidence (1)

src/BlazorWebView/tests/MauiBlazorWebView.UnitTests/Extensions_Tests.cs:46

  • [nitpick] The test method name suggests a false return value, but the assertion expects true. Consider renaming the method to reflect the correct expected outcome.
public void IsBaseOfPage_IgnoresDotInQuery_AndReturnsFalse_WhenNotBase()
@dotnet-policy-service dotnet-policy-service Bot added the community ✨ Community Contribution label May 16, 2025
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Hey there @@tw4! Thank you so much for your PR! Someone from the team will get assigned to your PR shortly and we'll get it reviewed.

@jsuarezruiz jsuarezruiz added the area-blazor Blazor Hybrid / Desktop, BlazorWebView label May 19, 2025
@jsuarezruiz

Copy link
Copy Markdown
Contributor

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 3 pipeline(s).
@tw4
tw4 requested a review from jsuarezruiz May 19, 2025 07:15
Comment thread src/BlazorWebView/src/Maui/Extensions/UriExtensions.cs
@tw4

tw4 commented May 27, 2025

Copy link
Copy Markdown
Author

Can I request a review @jsuarezruiz

@MauiBot MauiBot added s/agent-changes-requested AI agent recommends changes - found a better alternative or issues s/agent-fix-win AI found a better alternative fix than the PR s/agent-reviewed PR was reviewed by AI agent workflow (full 4-phase review) labels Mar 22, 2026

@kubaflo kubaflo left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Could you please review the AI's summary?

- Remove custom subdomain host/path matching, preserve original
  Uri.IsBaseOf behavior as the scope of this fix is limited to
  query/fragment dot handling
- Use uri.AbsolutePath for Path.HasExtension check (core bug fix)
- Align test project with repo conventions: use $(_MauiDotNetTfm)
  and centralized package version variables
- Update subdomain test expectations to false (Uri.IsBaseOf does
  not match across different hosts)
@github-actions

github-actions Bot commented Mar 23, 2026

Copy link
Copy Markdown
Contributor

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.sh | bash -s -- 29560

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.ps1) } 29560"
@tw4

tw4 commented Mar 23, 2026

Copy link
Copy Markdown
Author

@kubaflo I've reviewed the AI summary and addressed the requested changes:

  1. Restored Uri.IsBaseOf semantics — removed custom subdomain host/path matching that broadened the original behavior beyond the bug scope.
  2. Aligned test project with repo conventions — switched to $(_MauiDotNetTfm) and centralized package version variables ($(CoverletCollectorPackageVersion), $(XunitPackageVersion)), removed redundant Microsoft.NET.Test.Sdk reference.
  3. Updated subdomain test expectations — all subdomain cases now expect false, consistent with Uri.IsBaseOf behavior.

The bug fix remains focused: Path.HasExtension is checked only on uri.AbsolutePath to avoid treating dots in query parameters/fragments as file extensions.

Could you please re-review?

@tw4
tw4 requested a review from kubaflo March 23, 2026 08:22
@MauiBot MauiBot added s/agent-approved AI agent recommends approval - PR fix is correct and optimal s/agent-fix-pr-picked AI could not beat the PR fix - PR is the best among all candidates and removed s/agent-changes-requested AI agent recommends changes - found a better alternative or issues s/agent-fix-win AI found a better alternative fix than the PR labels Mar 23, 2026

@kubaflo kubaflo left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Could you check the ai's summary?

@tw4

tw4 commented Jun 1, 2026

Copy link
Copy Markdown
Author

Hey @kubaflo, went through the AI summary.

Code review came back LGTM (high confidence) — the only suggestion was a cosmetic file rename, which I'll do (Extensions_Tests.csUriExtensions_Tests.cs to match the class name).

The gate failure is actually an infrastructure issue, not a real test failure — the verify script bailed out because of uncommitted files in its setup, before any tests ran. That's why try-fix-3 was picked as "winner" — but the summary itself notes that if you disregard the gate, the PR would be preferred, and that the PR fix is "technically cleaner".

On the actual diff: try-fix-3 swaps uri.GetComponents(UriComponents.Path, UriFormat.Unescaped) for Uri.UnescapeDataString(uri.AbsolutePath). They produce the same result for normal URLs, but GetComponents is the API designed for extracting URI path components — UnescapeDataString is meant for query string data and decodes a bit more aggressively. So I'd rather keep the current approach.

Pushing the rename shortly.

@kubaflo

kubaflo commented Jun 1, 2026

Copy link
Copy Markdown
Collaborator

/review -b feature/enhanced-reviewer

@MauiBot MauiBot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Expert Review — 2 findings

See inline comments for details.

[InlineData("this is not a uri!", false)]
[InlineData("https://example.com/", true)]
[InlineData("https://example.com/page/", true)]
[InlineData("https://example.com/page?weight=62.5", true)]

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[moderate] Regression Prevention — The regression case exercises https://example.com/..., but the failing BlazorWebView paths use platform app origins (https://0.0.0.1/... on Android and app://0.0.0.1/... on iOS/MacCatalyst). Add query-dot/fragment-dot cases for those actual origins so the test reproduces the platform scenarios this helper is used for, rather than only a generic HTTPS host.

MauiBot

This comment was marked as outdated.

@kubaflo

kubaflo commented Jun 6, 2026

Copy link
Copy Markdown
Collaborator

/review -b feature/enhanced-reviewer -p windows

@MauiBot MauiBot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Expert Review — 2 findings

See inline comments for details.

Assert.Equal(expected, result);
}

[Fact]

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[minor] Regression Prevention — Test duplication — Five of the six standalone [Fact] methods in this block duplicate [InlineData] cases that already exist in IsBaseOfPage_HandlesVariousUris above:

Fact method Duplicate Theory InlineData
IsBaseOfPage_ReturnsFalse_WhenPathHasFileExtension (line 57) ("https://example.com/file.txt", false) (line 17)
IsBaseOfPage_ReturnsTrue_WhenUriIsBaseItself (line 63) ("https://example.com/", true) (line 13)
IsBaseOfPage_IgnoresDotInQuery_WhenBaseUriMatches (line 70) ("https://example.com/page?weight=62.5", true) (line 15)
IsBaseOfPage_ReturnsFalse_WhenSchemeDiffersFromBase (line 77) ("ftp://example.com/page", false) (line 19)
IsBaseOfPage_TreatsFragmentWithDotAsNoExtension (line 100) ("https://example.com/page#section.1", true) (line 16)

Consider removing these duplicates and consolidating only the non-redundant case (IsBaseOfPage_DoesNotTreatDotInQueryAsExtension) into the Theory, or keep it as a named Fact with an issue-reference comment (see next finding). Duplicate test cases inflate pass counts without adding coverage and make it harder to identify genuine regression tests at a glance.

}

[Fact]
public void IsBaseOfPage_DoesNotTreatDotInQueryAsExtension()

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[minor] Regression Prevention — Missing issue reference on primary regression testIsBaseOfPage_DoesNotTreatDotInQueryAsExtension is the most important test in this file: it is the direct reproduction of issue #25689 (?weight=62.5 being incorrectly identified as a file extension). Add a comment linking it to the issue so reviewers and future maintainers can trace it back to its origin:

// Regression test for https://github.com/dotnet/maui/issues/25689
// A URL with a dot in the query parameter (e.g. ?weight=62.5) must not be
// treated as a file-extension path and must be allowed to fall back to the host page.
[Fact]
public void IsBaseOfPage_DoesNotTreatDotInQueryAsExtension()

Without this comment, the test is indistinguishable from the duplicate facts above and its specific regression value is invisible.

MauiBot

This comment was marked as outdated.

@kubaflo kubaflo left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Could you please check the ai's suggestions?

The regression tests only exercised a generic https://example.com host,
but BlazorWebView uses https://0.0.0.1/ (Android/Windows) and app://0.0.0.1/
(iOS/MacCatalyst) as the app origin. Add a theory covering dot-in-query,
dot-in-fragment and real-extension cases for those actual origins so the
issue dotnet#25689 scenario is reproduced on the platforms it affects.
@tw4

tw4 commented Jun 7, 2026

Copy link
Copy Markdown
Author

Hey, thanks for the heads up! Went through the AI comments one by one.

Cleaned up the duplicate tests first — a bunch of the [Fact] ones were just repeating cases I already had in the [Theory], so no point keeping both. Also dropped a comment on the ?weight=62.5 test pointing back to #25689 so it's clear later why it's there.

The one that actually mattered was the note about the origins. I was only testing against https://example.com, but in real life BlazorWebView runs on https://0.0.0.1/ for Android/Windows and app://0.0.0.1/ for iOS/Mac. So I added tests using those actual origins (dot in query, dot in fragment, plus a real .json file to make sure that still gets blocked). Good catch, makes the test much closer to the real bug.

Let me know if there's anything else you'd like me to tweak.

@kubaflo

kubaflo commented Jun 7, 2026

Copy link
Copy Markdown
Collaborator

/review -b feature/enhanced-reviewer

@MauiBot MauiBot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

AI Review Summary

@tw4 — new AI review results are available based on this last commit: a856301.
Test IsBaseOfPage against real platform app origins To request a fresh review after new comments or commits, comment /review rerun.

Gate Passed Code Review In Review Confidence High Platform Android

Review Sessions — click to expand
Gate — Test Before & After Fix

Gate Result: ✅ PASSED

Platform: ANDROID · Base: main · Merge base: e904e900

Test Without Fix (expect FAIL) With Fix (expect PASS)
🧪 UriExtensions_Tests UriExtensions_Tests 🛠️ BUILD ERROR ✅ PASS — 24s
🔴 Without fix — 🧪 UriExtensions_Tests: 🛠️ BUILD ERROR · 136s
  Determining projects to restore...
  Restored /home/vsts/work/1/s/src/Graphics/src/Graphics/Graphics.csproj (in 1.58 sec).
  Restored /home/vsts/work/1/s/src/BlazorWebView/tests/MauiBlazorWebView.UnitTests/MauiBlazorWebView.UnitTests.csproj (in 6.41 sec).
  Restored /home/vsts/work/1/s/src/Essentials/src/Essentials.csproj (in 3.39 sec).
  Restored /home/vsts/work/1/s/src/BlazorWebView/src/Maui/Microsoft.AspNetCore.Components.WebView.Maui.csproj (in 10.85 sec).
  Restored /home/vsts/work/1/s/src/Core/src/Core.csproj (in 2.49 sec).
  Restored /home/vsts/work/1/s/src/Controls/src/Core/Controls.Core.csproj (in 224 ms).
  1 of 7 projects are up-to-date for restore.
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14306429
  Graphics -> /home/vsts/work/1/s/artifacts/bin/Graphics/Debug/net10.0/Microsoft.Maui.Graphics.dll
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14306429
  Essentials -> /home/vsts/work/1/s/artifacts/bin/Essentials/Debug/net10.0/Microsoft.Maui.Essentials.dll
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14306429
  Core -> /home/vsts/work/1/s/artifacts/bin/Core/Debug/net10.0/Microsoft.Maui.dll
  Controls.BindingSourceGen -> /home/vsts/work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14306429
  Controls.Core -> /home/vsts/work/1/s/artifacts/bin/Controls.Core/Debug/net10.0/Microsoft.Maui.Controls.dll
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14306429
  Microsoft.AspNetCore.Components.WebView.Maui -> /home/vsts/work/1/s/artifacts/bin/Microsoft.AspNetCore.Components.WebView.Maui/Debug/net10.0/Microsoft.AspNetCore.Components.WebView.Maui.dll
/home/vsts/work/1/s/src/BlazorWebView/tests/MauiBlazorWebView.UnitTests/UriExtensions_Tests.cs(51,25): error CS1061: 'Uri' does not contain a definition for 'IsBaseOfPage' and no accessible extension method 'IsBaseOfPage' accepting a first argument of type 'Uri' could be found (are you missing a using directive or an assembly reference?) [/home/vsts/work/1/s/src/BlazorWebView/tests/MauiBlazorWebView.UnitTests/MauiBlazorWebView.UnitTests.csproj]
/home/vsts/work/1/s/src/BlazorWebView/tests/MauiBlazorWebView.UnitTests/UriExtensions_Tests.cs(63,23): error CS1061: 'Uri' does not contain a definition for 'IsBaseOfPage' and no accessible extension method 'IsBaseOfPage' accepting a first argument of type 'Uri' could be found (are you missing a using directive or an assembly reference?) [/home/vsts/work/1/s/src/BlazorWebView/tests/MauiBlazorWebView.UnitTests/MauiBlazorWebView.UnitTests.csproj]
/home/vsts/work/1/s/src/BlazorWebView/tests/MauiBlazorWebView.UnitTests/UriExtensions_Tests.cs(78,33): error CS1061: 'Uri' does not contain a definition for 'IsBaseOfPage' and no accessible extension method 'IsBaseOfPage' accepting a first argument of type 'Uri' could be found (are you missing a using directive or an assembly reference?) [/home/vsts/work/1/s/src/BlazorWebView/tests/MauiBlazorWebView.UnitTests/MauiBlazorWebView.UnitTests.csproj]

🟢 With fix — 🧪 UriExtensions_Tests: PASS ✅ · 24s
  Determining projects to restore...
  All projects are up-to-date for restore.
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14306429
  Graphics -> /home/vsts/work/1/s/artifacts/bin/Graphics/Debug/net10.0/Microsoft.Maui.Graphics.dll
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14306429
  Essentials -> /home/vsts/work/1/s/artifacts/bin/Essentials/Debug/net10.0/Microsoft.Maui.Essentials.dll
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14306429
  Core -> /home/vsts/work/1/s/artifacts/bin/Core/Debug/net10.0/Microsoft.Maui.dll
  Controls.BindingSourceGen -> /home/vsts/work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14306429
  Controls.Core -> /home/vsts/work/1/s/artifacts/bin/Controls.Core/Debug/net10.0/Microsoft.Maui.Controls.dll
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14306429
  Microsoft.AspNetCore.Components.WebView.Maui -> /home/vsts/work/1/s/artifacts/bin/Microsoft.AspNetCore.Components.WebView.Maui/Debug/net10.0/Microsoft.AspNetCore.Components.WebView.Maui.dll
  MauiBlazorWebView.UnitTests -> /home/vsts/work/1/s/artifacts/bin/MauiBlazorWebView.UnitTests/Debug/net10.0/Microsoft.Maui.MauiBlazorWebView.UnitTests.dll
Test run for /home/vsts/work/1/s/artifacts/bin/MauiBlazorWebView.UnitTests/Debug/net10.0/Microsoft.Maui.MauiBlazorWebView.UnitTests.dll (.NETCoreApp,Version=v10.0)
VSTest version 18.0.1 (x64)

Starting test execution, please wait...
A total of 1 test files matched the specified pattern.
[xUnit.net 00:00:00.01] xUnit.net VSTest Adapter v2.8.2+699d445a1a (64-bit .NET 10.0.0)
[xUnit.net 00:00:00.29]   Discovering: Microsoft.Maui.MauiBlazorWebView.UnitTests
[xUnit.net 00:00:00.53]   Discovered:  Microsoft.Maui.MauiBlazorWebView.UnitTests
[xUnit.net 00:00:00.56]   Starting:    Microsoft.Maui.MauiBlazorWebView.UnitTests
  Passed Microsoft.Maui.MauiBlazorWebView.UnitTests.UriExtensions_Tests.IsBaseOfPage_HandlesVariousUris(uriString: "https://subdomain.example.com/path/with space", expected: False) [24 ms]
  Passed Microsoft.Maui.MauiBlazorWebView.UnitTests.UriExtensions_Tests.IsBaseOfPage_HandlesVariousUris(uriString: "https://example.com/file.txt", expected: False) [< 1 ms]
  Passed Microsoft.Maui.MauiBlazorWebView.UnitTests.UriExtensions_Tests.IsBaseOfPage_HandlesVariousUris(uriString: "https://example.com/test", expected: True) [< 1 ms]
  Passed Microsoft.Maui.MauiBlazorWebView.UnitTests.UriExtensions_Tests.IsBaseOfPage_HandlesVariousUris(uriString: "https://example.com/page?weight=62.5", expected: True) [< 1 ms]
  Passed Microsoft.Maui.MauiBlazorWebView.UnitTests.UriExtensions_Tests.IsBaseOfPage_HandlesVariousUris(uriString: "https://example.com/page.json?foo=bar", expected: False) [< 1 ms]
  Passed Microsoft.Maui.MauiBlazorWebView.UnitTests.UriExtensions_Tests.IsBaseOfPage_HandlesVariousUris(uriString: "https://subdomain.example.com/page.html", expected: False) [< 1 ms]
  Passed Microsoft.Maui.MauiBlazorWebView.UnitTests.UriExtensions_Tests.IsBaseOfPage_HandlesVariousUris(uriString: null, expected: False) [< 1 ms]
  Passed Microsoft.Maui.MauiBlazorWebView.UnitTests.UriExtensions_Tests.IsBaseOfPage_HandlesVariousUris(uriString: "https://subdomain.example.com/page", expected: False) [< 1 ms]
  Passed Microsoft.Maui.MauiBlazorWebView.UnitTests.UriExtensions_Tests.IsBaseOfPage_HandlesVariousUris(uriString: "https://subdomain.example.com/page/", expected: False) [< 1 ms]
  Passed Microsoft.Maui.MauiBlazorWebView.UnitTests.UriExtensions_Tests.IsBaseOfPage_HandlesVariousUris(uriString: "https://example.com/path/with%20encoded%20space", expected: True) [6 ms]
  Passed Microsoft.Maui.MauiBlazorWebView.UnitTests.UriExtensions_Tests.IsBaseOfPage_HandlesVariousUris(uriString: "", expected: False) [< 1 ms]
  Passed Microsoft.Maui.MauiBlazorWebView.UnitTests.UriExtensions_Tests.IsBaseOfPage_HandlesVariousUris(uriString: "https://subdomain.example.com/test", expected: False) [< 1 ms]
  Passed Microsoft.Maui.MauiBlazorWebView.UnitTests.UriExtensions_Tests.IsBaseOfPage_HandlesVariousUris(uriString: "https://example.com/page?param=value&param2=value2", expected: True) [< 1 ms]
  Passed Microsoft.Maui.MauiBlazorWebView.UnitTests.UriExtensions_Tests.IsBaseOfPage_HandlesVariousUris(uriString: "page/subpage", expected: False) [< 1 ms]
  Passed Microsoft.Maui.MauiBlazorWebView.UnitTests.UriExtensions_Tests.IsBaseOfPage_HandlesVariousUris(uriString: "https://example.com/page.html", expected: False) [< 1 ms]
  Passed Microsoft.Maui.MauiBlazorWebView.UnitTests.UriExtensions_Tests.IsBaseOfPage_HandlesVariousUris(uriString: "https://subdomain.example.com/file.txt", expected: False) [< 1 ms]
  Passed Microsoft.Maui.MauiBlazorWebView.UnitTests.UriExtensions_Tests.IsBaseOfPage_HandlesVariousUris(uriString: "https://subdomain.example.com/folder/file.exe", expected: False) [< 1 ms]
  Passed Microsoft.Maui.MauiBlazorWebView.UnitTests.UriExtensions_Tests.IsBaseOfPage_HandlesVariousUris(uriString: "ftp://subdomain.example.com/page", expected: False) [< 1 ms]
  Passed Microsoft.Maui.MauiBlazorWebView.UnitTests.UriExtensions_Tests.IsBaseOfPage_HandlesVariousUris(uriString: "/relative/path", expected: False) [< 1 ms]
  Passed Microsoft.Maui.MauiBlazorWebView.UnitTests.UriExtensions_Tests.IsBaseOfPage_HandlesVariousUris(uriString: "https://example.com/", expected: True) [< 1 ms]
  Passed Microsoft.Maui.MauiBlazorWebView.UnitTests.UriExtensions_Tests.IsBaseOfPage_HandlesVariousUris(uriString: "https://example.com/path/with/.dot/segment", expected: True) [< 1 ms]
  Passed Microsoft.Maui.MauiBlazorWebView.UnitTests.UriExtensions_Tests.IsBaseOfPage_HandlesVariousUris(uriString: "this is not a uri!", expected: False) [< 1 ms]
  Passed Microsoft.Maui.MauiBlazorWebView.UnitTests.UriExtensions_Tests.IsBaseOfPage_HandlesVariousUris(uriString: "https://example.com/page#section.1", expected: True) [< 1 ms]
  Passed Microsoft.Maui.MauiBlazorWebView.UnitTests.UriExtensions_Tests.IsBaseOfPage_HandlesVariousUris(uriString: "HTTPS://EXAMPLE.COM/PAGE", expected: True) [< 1 ms]
  Passed Microsoft.Maui.MauiBlazorWebView.UnitTests.UriExtensions_Tests.IsBaseOfPage_HandlesVariousUris(uriString: "https://subdomain.example.com/path/with/.dot/segme"···, expected: False) [< 1 ms]
  Passed Microsoft.Maui.MauiBlazorWebView.UnitTests.UriExtensions_Tests.IsBaseOfPage_HandlesVariousUris(uriString: "https://subdomain.example.com/page?param=value&par"···, expected: False) [< 1 ms]
  Passed Microsoft.Maui.MauiBlazorWebView.UnitTests.UriExtensions_Tests.IsBaseOfPage_HandlesVariousUris(uriString: "https://subdomain.example.com/page?weight=62.5", expected: False) [< 1 ms]
  Passed Microsoft.Maui.MauiBlazorWebView.UnitTests.UriExtensions_Tests.IsBaseOfPage_HandlesVariousUris(uriString: "https://subdomain.example.com/", expected: False) [< 1 ms]
  Passed Microsoft.Maui.MauiBlazorWebView.UnitTests.UriExtensions_Tests.IsBaseOfPage_HandlesVariousUris(uriString: "https://example.com/folder/subfolder/", expected: True) [< 1 ms]
  Passed Microsoft.Maui.MauiBlazorWebView.UnitTests.UriExtensions_Tests.IsBaseOfPage_HandlesVariousUris(uriString: "HTTPS://SUBDOMAIN.EXAMPLE.COM/PAGE", expected: False) [< 1 ms]
  Passed Microsoft.Maui.MauiBlazorWebView.UnitTests.UriExtensions_Tests.IsBaseOfPage_HandlesVariousUris(uriString: "https://subdomain.example.com/page.json?foo=bar", expected: False) [< 1 ms]
  Passed Microsoft.Maui.MauiBlazorWebView.UnitTests.UriExtensions_Tests.IsBaseOfPage_HandlesVariousUris(uriString: "https://example.com/path/with space", expected: True) [< 1 ms]
  Passed Microsoft.Maui.MauiBlazorWebView.UnitTests.UriExtensions_Tests.IsBaseOfPage_HandlesVariousUris(uriString: "https://subdomain.example.com/page#section.1", expected: False) [< 1 ms]
  Passed Microsoft.Maui.MauiBlazorWebView.UnitTests.UriExtensions_Tests.IsBaseOfPage_HandlesVariousUris(uriString: "https://example.com/page", expected: True) [< 1 ms]
  Passed Microsoft.Maui.MauiBlazorWebView.UnitTests.UriExtensions_Tests.IsBaseOfPage_HandlesVariousUris(uriString: "https://subdomain.example.com/folder/subfolder/", expected: False) [< 1 ms]
  Passed Microsoft.Maui.MauiBlazorWebView.UnitTests.UriExtensions_Tests.IsBaseOfPage_HandlesVariousUris(uriString: "https://example.com/page/", expected: True) [< 1 ms]
  Passed Microsoft.Maui.MauiBlazorWebView.UnitTests.UriExtensions_Tests.IsBaseOfPage_HandlesVariousUris(uriString: "ftp://example.com/page", expected: False) [< 1 ms]
  Passed Microsoft.Maui.MauiBlazorWebView.UnitTests.UriExtensions_Tests.IsBaseOfPage_HandlesVariousUris(uriString: "https://subdomain.example.com/path/with%20encoded%"···, expected: False) [< 1 ms]
  Passed Microsoft.Maui.MauiBlazorWebView.UnitTests.UriExtensions_Tests.IsBaseOfPage_HandlesVariousUris(uriString: "https://example.com/folder/file.exe", expected: False) [< 1 ms]
  Passed Microsoft.Maui.MauiBlazorWebView.UnitTests.UriExtensions_Tests.IsBaseOfPage_HandlesPlatformAppOrigins(baseUri: "https://0.0.0.1/", uriString: "https://0.0.0.1/customer.json", expected: False) [< 1 ms]
  Passed Microsoft.Maui.MauiBlazorWebView.UnitTests.UriExtensions_Tests.IsBaseOfPage_HandlesPlatformAppOrigins(baseUri: "app://0.0.0.1/", uriString: "app://0.0.0.1/customer?weight=62.5", expected: True) [4 ms]
  Passed Microsoft.Maui.MauiBlazorWebView.UnitTests.UriExtensions_Tests.IsBaseOfPage_HandlesPlatformAppOrigins(baseUri: "https://0.0.0.1/", uriString: "https://0.0.0.1/customer#section.1", expected: True) [< 1 ms]
  Passed Microsoft.Maui.MauiBlazorWebView.UnitTests.UriExtensions_Tests.IsBaseOfPage_HandlesPlatformAppOrigins(baseUri: "https://0.0.0.1/", uriString: "https://0.0.0.1/customer?weight=62.5", expected: True) [< 1 ms]
  Passed Microsoft.Maui.MauiBlazorWebView.UnitTests.UriExtensions_Tests.IsBaseOfPage_HandlesPlatformAppOrigins(baseUri: "app://0.0.0.1/", uriString: "app://0.0.0.1/customer.json", expected: False) [< 1 ms]
  Passed Microsoft.Maui.MauiBlazorWebView.UnitTests.UriExtensions_Tests.IsBaseOfPage_HandlesPlatformAppOrigins(baseUri: "app://0.0.0.1/", uriString: "app://0.0.0.1/customer#section.1", expected: True) [< 1 ms]
[xUnit.net 00:00:00.93]   Finished:    Microsoft.Maui.MauiBlazorWebView.UnitTests
  Passed Microsoft.Maui.MauiBlazorWebView.UnitTests.UriExtensions_Tests.IsBaseOfPage_DoesNotTreatDotInQueryAsExtension [< 1 ms]

Test Run Successful.
Total tests: 46
     Passed: 46
 Total time: 2.6104 Seconds

⚠️ Failure Details

  • 🛠️ UriExtensions_Tests without fix: build failed before tests could run
    • /home/vsts/work/1/s/src/BlazorWebView/tests/MauiBlazorWebView.UnitTests/UriExtensions_Tests.cs(51,25): error CS1061: 'Uri' does not contain a definition for 'IsBaseOfPage' and no accessible extension ...
📁 Fix files reverted (11 files)
  • Microsoft.Maui-dev.sln
  • Microsoft.Maui-mac.slnf
  • Microsoft.Maui-vscode.sln
  • Microsoft.Maui-windows.slnf
  • Microsoft.Maui.LegacyControlGallery.sln
  • Microsoft.Maui.sln
  • eng/cake/dotnet.cake
  • eng/helix.proj
  • eng/pipelines/ci-copilot.yml
  • src/BlazorWebView/src/Maui/Extensions/UriExtensions.cs
  • src/BlazorWebView/src/Maui/Properties/AssemblyInfo.cs

Pre-Flight — Context & Validation

Issue: #25689 - Blazor Hybrid Webview cannot be force reloaded for urls containing query parameters with a dot (.)
PR: #29560 - [BlazorWebView] Fixed Allow force reload for URLs with dots in query parameters
Platforms Affected: Android, iOS, MacCatalyst BlazorWebView (issue labels Android/iOS; helper used by Android/iOS handlers)
Files Changed: 10 implementation/build wiring, 2 test

Key Findings

  • Root cause: Path.HasExtension(uriString) evaluated the entire URI, so query or fragment dots such as ?weight=62.5 were treated as path file extensions and prevented page fallback/force reload.
  • PR fix parses absolute URIs, checks only the URI path via GetComponents(UriComponents.Path, UriFormat.Unescaped), then preserves Uri.IsBaseOf semantics for scheme/host/path matching.
  • Regression coverage is unit-test based and now wired into eng/cake/dotnet.cake and eng/helix.proj; prior review comments specifically requested this wiring and platform-origin cases.
  • Impacted test type: Unit tests (src/BlazorWebView/tests/MauiBlazorWebView.UnitTests). No UI category selected for this review because the PR adds helper-level unit coverage rather than UI tests.

Code Review Summary

Verdict: LGTM
Confidence: high
Errors: 0 | Warnings: 0 | Suggestions: 3

Key code review findings:

  • 💡 PR description is stale: it says uri.AbsolutePath, while code uses uri.GetComponents(UriComponents.Path, UriFormat.Unescaped); the committed code is more robust.
  • 💡 Minor formatting blank line in src/BlazorWebView/src/Maui/Properties/AssemblyInfo.cs.
  • 💡 A named regression [Fact] partially duplicates a theory case, but the issue-reference comment makes it discoverable.

Fix Candidates

# Source Approach Test Result Files Changed Notes
PR PR #29560 Parse URI, check only unescaped path component for extension, preserve Uri.IsBaseOf, add/wire BlazorWebView unit tests ✅ PASSED (Gate) UriExtensions.cs, AssemblyInfo.cs, BlazorWebView unit test project, solution/test wiring Original PR; gate result supplied as passed

Code Review — Deep Analysis

Code Review — PR #29560

Independent Assessment

What this changes: IsBaseOfPage in UriExtensions.cs is refactored to parse the URI first, then extract only the path component via uri.GetComponents(UriComponents.Path, UriFormat.Unescaped) before running Path.HasExtension. Two additional guards are added: a string.IsNullOrWhiteSpace early-exit and Uri.TryCreate(..., UriKind.Absolute, ...) to reject relative or malformed inputs. A new MauiBlazorWebView.UnitTests project is created and wired into eng/cake/dotnet.cake and eng/helix.proj.

Inferred motivation: The old code passed the entire raw URI string to Path.HasExtension. A URL like https://example.com/page?weight=62.5 has .5 near its end, which Path.HasExtension sees as a file extension, so the method returned false (not a page), blocking force-reload. The bug affects Android (WebKitWebViewClient, lines 118, 146) and iOS (BlazorWebViewHandler.iOS.cs, line 317) — both callers pass raw URL strings.

Approach soundness: The fix is direct and well-scoped. Using GetComponents(UriComponents.Path, UriFormat.Unescaped) is strictly superior to the PR description's stated uri.AbsolutePath because it also decodes percent-encoded characters (e.g., /path/with%2Eext -> /path/with.ext) before the extension check, catching disguised extensions. The scheme and host are still validated by the final IsBaseOf call. No alternative simpler fix exists — stripping query strings with regex would be fragile.


Reconciliation with PR Narrative

Author claims: Bug is in Path.HasExtension(uriString) applied to the full raw URI string; fix switches to uri.AbsolutePath; adds input validation with IsNullOrWhiteSpace and TryCreate.

Agreement: The bug description and root cause analysis are exactly right. The claimed behavioral outcome is correct.

Disagreement / discrepancy: The PR description says the fix uses uri.AbsolutePath, but the committed code uses uri.GetComponents(UriComponents.Path, UriFormat.Unescaped). The actual code is more correct than the description states (handles percent-encoded dots) — this looks like the description was written for an earlier iteration and wasn't updated after the final commit.


Findings

💡 Suggestion — PR description is stale: claims uri.AbsolutePath, code uses GetComponents

src/BlazorWebView/src/Maui/Extensions/UriExtensions.cs line 21

The PR description's "After" snippet shows Path.HasExtension(uri.AbsolutePath), but the committed code uses Path.HasExtension(uri.GetComponents(UriComponents.Path, UriFormat.Unescaped)). The committed code is the right choice because it handles %2E-encoded dots that AbsolutePath would miss.

💡 Suggestion — Spurious blank line in AssemblyInfo.cs

src/BlazorWebView/src/Maui/Properties/AssemblyInfo.cs lines 4-5

The added using System.Runtime.CompilerServices; introduces a double blank line before [assembly: Preserve]. Minor formatting issue.

💡 Suggestion — IsBaseOfPage_DoesNotTreatDotInQueryAsExtension duplicates a Theory case

src/BlazorWebView/tests/MauiBlazorWebView.UnitTests/UriExtensions_Tests.cs line 59

The standalone [Fact] is structurally already covered by the weight=62.5 theory case. Keeping it with the issue-reference comment is acceptable for discoverability.


Devil's Advocate

GetComponents is safe after TryCreate. UriKind.Absolute accepts Android https://0.0.0.1/... and iOS/MacCatalyst app://0.0.0.1/... origins, which the tests cover. Windows does not call this helper. The unit test project is wired into both local cake unit-test and Helix lists.


Verdict: LGTM

Confidence: high

Summary: The fix is mechanically correct: extracting only the URI path component before Path.HasExtension directly eliminates the false-positive that blocked force-reload for URLs with dots in query parameters or fragments. Tests are comprehensive, wired into CI, and cover the real platform origins. Findings are suggestions only.


Fix — Analysis & Comparison

Fix Candidates

# Source Approach Test Result Files Changed Notes
1 try-fix Parse URI and check only uri.Segments final segment for extension ✅ PASS 2 files Current tests pass, but encoded-dot paths such as file%2Etxt are weaker than PR fix because Uri.Segments remains percent-encoded
2 try-fix Parse URI, slice final AbsolutePath segment, decode with Uri.UnescapeDataString, then check extension ✅ PASS 2 files Handles encoded dots, but manually reimplements behavior the PR gets from GetComponents(UriComponents.Path, UriFormat.Unescaped)
PR PR #29560 Parse URI, check unescaped path component with GetComponents(UriComponents.Path, UriFormat.Unescaped), preserve Uri.IsBaseOf, add/wire BlazorWebView unit tests ✅ PASSED (Gate) 12 files Original PR; gate result supplied as passed

Cross-Pollination

Model Round New Ideas? Details
maui-expert-reviewer 1 Yes Suggested final-segment strategy; noted encoded-dot weakness
maui-expert-reviewer 2 Yes Suggested explicit final-segment decode to address encoded dots
maui-expert-reviewer 3 No Correct approaches converge on stripping query/fragment, decoding percent-encoding, and checking path extension; PR fix is the smallest BCL-native expression of that invariant

Exhausted: Yes
Selected Fix: PR #29560 — It passes the supplied gate, is more robust than candidate #1, and is simpler/less manual than candidate #2. No candidate is demonstrably better than the PR fix.


Report — Final Recommendation

Comparative Report — PR #29560

Candidates compared

Candidate Approach Regression result Assessment
pr Parse an absolute URI, check Path.HasExtension only on uri.GetComponents(UriComponents.Path, UriFormat.Unescaped), then preserve baseUri.IsBaseOf(uri). Adds and wires BlazorWebView unit tests. ✅ Passed gate Best balance of correctness, simplicity, and coverage.
pr-plus-reviewer Same as pr; expert reviewer produced no actionable findings to apply. ✅ Same as pr Equivalent to pr; no improvement over submitted fix.
try-fix-1 Parse an absolute URI and check only the final uri.Segments entry for an extension. ✅ Passed candidate tests Correct for the reported query/fragment-dot bug, but weaker than pr because Uri.Segments remains percent-encoded, so encoded-dot file paths such as file%2Etxt can evade extension detection.
try-fix-2 Parse an absolute URI, manually slice the final AbsolutePath segment, decode it with Uri.UnescapeDataString, and check that segment for an extension. ✅ Passed candidate tests Robust, but more manual and complex than pr; it reimplements behavior the PR gets from BCL URI component extraction.

Ranking

  1. pr — The submitted fix wins. It passed the supplied gate, fixes the root cause by checking only the unescaped path component, preserves existing IsBaseOf semantics, and includes CI-wired unit coverage for the relevant platform origins.
  2. pr-plus-reviewer — Equivalent to pr because the expert reviewer found no actionable inline issues. It ranks just below pr only because it is not a distinct improvement.
  3. try-fix-2 — Also passes tests and handles encoded dots, but it is more verbose and manually slices/decodes URI segments where GetComponents(UriComponents.Path, UriFormat.Unescaped) is clearer and less error-prone.
  4. try-fix-1 — Passes the candidate tests but is least robust among passing candidates because it checks percent-encoded segments without decoding them.

No candidate failed regression tests, so ranking is based on correctness margin, implementation simplicity, and maintainability.

Winning candidate

Winner: pr

The raw PR fix is the best candidate. It uses the most direct BCL-native expression of the desired invariant: ignore query and fragment data for file-extension detection while preserving URI base checks. The expert review did not identify any actionable changes, so pr-plus-reviewer does not improve on it.


Future Action — review latest findings

No alternative fix was selected for this run. Review the session findings and CI results before merging.

@kubaflo

kubaflo commented Jun 16, 2026

Copy link
Copy Markdown
Collaborator

/review rerun

@kubaflo
kubaflo changed the base branch from main to inflight/current June 21, 2026 14:15
@kubaflo
kubaflo merged commit ee017f2 into dotnet:inflight/current Jun 21, 2026
3 of 4 checks passed
@github-actions github-actions Bot added this to the .NET 10 SR9 milestone Jun 21, 2026
PureWeen pushed a commit that referenced this pull request Jun 22, 2026
…parameters (#29560)

<!-- Please let the below note in for people that find this PR -->
> [!NOTE]  
> Are you waiting for the changes in this PR to be merged?  
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->

### Description of Change

This PR fixes a bug in `BlazorWebView` where URLs containing dots (`.`)
in **query parameters** (e.g., `?weight=62.5`) could not be force
reloaded. The issue was caused by using `Path.HasExtension(uriString)`,
which mistakenly treated dots in query strings as if they were part of a
file extension.

---

#### ❌ Before

The original logic:

```csharp
if (Path.HasExtension(uriString))
    return false;
```

This evaluates the entire URI string — including query parameters —
which incorrectly caused `?value=62.5` to be treated as a file
reference, breaking reload behavior.

---

#### ✅ After

This PR introduces a safer and more accurate approach:

```csharp
if (Path.HasExtension(uri.AbsolutePath))
    return false;
```

Along with additional improvements:

* Validates input with `string.IsNullOrWhiteSpace`
* Uses `Uri.TryCreate` with `UriKind.Absolute` to safely parse the input
and reject relative or malformed URIs
* Scheme/host matching is preserved through `Uri.IsBaseOf`, so URIs
whose scheme or host does not match the configured base URI are still
rejected as before

This ensures that only the actual path is evaluated for file extensions,
allowing query strings to contain dots without affecting navigation or
reload logic.

---

### Issues Fixed

Fixes #25689

Cover test result
<img width="477" alt="Screenshot 2025-05-16 at 22 54 41"
src="https://github.com/user-attachments/assets/55e5948b-17e6-4abd-9fad-d01172855c43"
/>


---

**Note:** @mattleibow  
The previous PR might have been truly cursed 😅 — I created a new branch,
rewrote the unit test project from scratch, and everything worked like a
charm this time.
No issues so far, and I'm optimistic GitHub Actions will behave too!
🧙‍♂️✨

Also, big thanks to @mattleibow for the support and guidance — your
insights helped me see things more clearly! 🙏
kubaflo pushed a commit that referenced this pull request Jun 25, 2026
…parameters (#29560)

<!-- Please let the below note in for people that find this PR -->
> [!NOTE]  
> Are you waiting for the changes in this PR to be merged?  
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->

### Description of Change

This PR fixes a bug in `BlazorWebView` where URLs containing dots (`.`)
in **query parameters** (e.g., `?weight=62.5`) could not be force
reloaded. The issue was caused by using `Path.HasExtension(uriString)`,
which mistakenly treated dots in query strings as if they were part of a
file extension.

---

#### ❌ Before

The original logic:

```csharp
if (Path.HasExtension(uriString))
    return false;
```

This evaluates the entire URI string — including query parameters —
which incorrectly caused `?value=62.5` to be treated as a file
reference, breaking reload behavior.

---

#### ✅ After

This PR introduces a safer and more accurate approach:

```csharp
if (Path.HasExtension(uri.AbsolutePath))
    return false;
```

Along with additional improvements:

* Validates input with `string.IsNullOrWhiteSpace`
* Uses `Uri.TryCreate` with `UriKind.Absolute` to safely parse the input
and reject relative or malformed URIs
* Scheme/host matching is preserved through `Uri.IsBaseOf`, so URIs
whose scheme or host does not match the configured base URI are still
rejected as before

This ensures that only the actual path is evaluated for file extensions,
allowing query strings to contain dots without affecting navigation or
reload logic.

---

### Issues Fixed

Fixes #25689

Cover test result
<img width="477" alt="Screenshot 2025-05-16 at 22 54 41"
src="https://github.com/user-attachments/assets/55e5948b-17e6-4abd-9fad-d01172855c43"
/>


---

**Note:** @mattleibow  
The previous PR might have been truly cursed 😅 — I created a new branch,
rewrote the unit test project from scratch, and everything worked like a
charm this time.
No issues so far, and I'm optimistic GitHub Actions will behave too!
🧙‍♂️✨

Also, big thanks to @mattleibow for the support and guidance — your
insights helped me see things more clearly! 🙏
kubaflo pushed a commit that referenced this pull request Jul 3, 2026
…parameters (#29560)

<!-- Please let the below note in for people that find this PR -->
> [!NOTE]  
> Are you waiting for the changes in this PR to be merged?  
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->

### Description of Change

This PR fixes a bug in `BlazorWebView` where URLs containing dots (`.`)
in **query parameters** (e.g., `?weight=62.5`) could not be force
reloaded. The issue was caused by using `Path.HasExtension(uriString)`,
which mistakenly treated dots in query strings as if they were part of a
file extension.

---

#### ❌ Before

The original logic:

```csharp
if (Path.HasExtension(uriString))
    return false;
```

This evaluates the entire URI string — including query parameters —
which incorrectly caused `?value=62.5` to be treated as a file
reference, breaking reload behavior.

---

#### ✅ After

This PR introduces a safer and more accurate approach:

```csharp
if (Path.HasExtension(uri.AbsolutePath))
    return false;
```

Along with additional improvements:

* Validates input with `string.IsNullOrWhiteSpace`
* Uses `Uri.TryCreate` with `UriKind.Absolute` to safely parse the input
and reject relative or malformed URIs
* Scheme/host matching is preserved through `Uri.IsBaseOf`, so URIs
whose scheme or host does not match the configured base URI are still
rejected as before

This ensures that only the actual path is evaluated for file extensions,
allowing query strings to contain dots without affecting navigation or
reload logic.

---

### Issues Fixed

Fixes #25689

Cover test result
<img width="477" alt="Screenshot 2025-05-16 at 22 54 41"
src="https://github.com/user-attachments/assets/55e5948b-17e6-4abd-9fad-d01172855c43"
/>


---

**Note:** @mattleibow  
The previous PR might have been truly cursed 😅 — I created a new branch,
rewrote the unit test project from scratch, and everything worked like a
charm this time.
No issues so far, and I'm optimistic GitHub Actions will behave too!
🧙‍♂️✨

Also, big thanks to @mattleibow for the support and guidance — your
insights helped me see things more clearly! 🙏
@kubaflo kubaflo mentioned this pull request Jul 6, 2026
kubaflo pushed a commit that referenced this pull request Jul 6, 2026
…parameters (#29560)

<!-- Please let the below note in for people that find this PR -->
> [!NOTE]  
> Are you waiting for the changes in this PR to be merged?  
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->

### Description of Change

This PR fixes a bug in `BlazorWebView` where URLs containing dots (`.`)
in **query parameters** (e.g., `?weight=62.5`) could not be force
reloaded. The issue was caused by using `Path.HasExtension(uriString)`,
which mistakenly treated dots in query strings as if they were part of a
file extension.

---

#### ❌ Before

The original logic:

```csharp
if (Path.HasExtension(uriString))
    return false;
```

This evaluates the entire URI string — including query parameters —
which incorrectly caused `?value=62.5` to be treated as a file
reference, breaking reload behavior.

---

#### ✅ After

This PR introduces a safer and more accurate approach:

```csharp
if (Path.HasExtension(uri.AbsolutePath))
    return false;
```

Along with additional improvements:

* Validates input with `string.IsNullOrWhiteSpace`
* Uses `Uri.TryCreate` with `UriKind.Absolute` to safely parse the input
and reject relative or malformed URIs
* Scheme/host matching is preserved through `Uri.IsBaseOf`, so URIs
whose scheme or host does not match the configured base URI are still
rejected as before

This ensures that only the actual path is evaluated for file extensions,
allowing query strings to contain dots without affecting navigation or
reload logic.

---

### Issues Fixed

Fixes #25689

Cover test result
<img width="477" alt="Screenshot 2025-05-16 at 22 54 41"
src="https://github.com/user-attachments/assets/55e5948b-17e6-4abd-9fad-d01172855c43"
/>


---

**Note:** @mattleibow  
The previous PR might have been truly cursed 😅 — I created a new branch,
rewrote the unit test project from scratch, and everything worked like a
charm this time.
No issues so far, and I'm optimistic GitHub Actions will behave too!
🧙‍♂️✨

Also, big thanks to @mattleibow for the support and guidance — your
insights helped me see things more clearly! 🙏
PureWeen pushed a commit that referenced this pull request Jul 7, 2026
…parameters (#29560)

<!-- Please let the below note in for people that find this PR -->
> [!NOTE]  
> Are you waiting for the changes in this PR to be merged?  
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->

### Description of Change

This PR fixes a bug in `BlazorWebView` where URLs containing dots (`.`)
in **query parameters** (e.g., `?weight=62.5`) could not be force
reloaded. The issue was caused by using `Path.HasExtension(uriString)`,
which mistakenly treated dots in query strings as if they were part of a
file extension.

---

#### ❌ Before

The original logic:

```csharp
if (Path.HasExtension(uriString))
    return false;
```

This evaluates the entire URI string — including query parameters —
which incorrectly caused `?value=62.5` to be treated as a file
reference, breaking reload behavior.

---

#### ✅ After

This PR introduces a safer and more accurate approach:

```csharp
if (Path.HasExtension(uri.AbsolutePath))
    return false;
```

Along with additional improvements:

* Validates input with `string.IsNullOrWhiteSpace`
* Uses `Uri.TryCreate` with `UriKind.Absolute` to safely parse the input
and reject relative or malformed URIs
* Scheme/host matching is preserved through `Uri.IsBaseOf`, so URIs
whose scheme or host does not match the configured base URI are still
rejected as before

This ensures that only the actual path is evaluated for file extensions,
allowing query strings to contain dots without affecting navigation or
reload logic.

---

### Issues Fixed

Fixes #25689

Cover test result
<img width="477" alt="Screenshot 2025-05-16 at 22 54 41"
src="https://github.com/user-attachments/assets/55e5948b-17e6-4abd-9fad-d01172855c43"
/>


---

**Note:** @mattleibow  
The previous PR might have been truly cursed 😅 — I created a new branch,
rewrote the unit test project from scratch, and everything worked like a
charm this time.
No issues so far, and I'm optimistic GitHub Actions will behave too!
🧙‍♂️✨

Also, big thanks to @mattleibow for the support and guidance — your
insights helped me see things more clearly! 🙏
PureWeen pushed a commit that referenced this pull request Jul 7, 2026
…parameters (#29560)

<!-- Please let the below note in for people that find this PR -->
> [!NOTE]  
> Are you waiting for the changes in this PR to be merged?  
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->

### Description of Change

This PR fixes a bug in `BlazorWebView` where URLs containing dots (`.`)
in **query parameters** (e.g., `?weight=62.5`) could not be force
reloaded. The issue was caused by using `Path.HasExtension(uriString)`,
which mistakenly treated dots in query strings as if they were part of a
file extension.

---

#### ❌ Before

The original logic:

```csharp
if (Path.HasExtension(uriString))
    return false;
```

This evaluates the entire URI string — including query parameters —
which incorrectly caused `?value=62.5` to be treated as a file
reference, breaking reload behavior.

---

#### ✅ After

This PR introduces a safer and more accurate approach:

```csharp
if (Path.HasExtension(uri.AbsolutePath))
    return false;
```

Along with additional improvements:

* Validates input with `string.IsNullOrWhiteSpace`
* Uses `Uri.TryCreate` with `UriKind.Absolute` to safely parse the input
and reject relative or malformed URIs
* Scheme/host matching is preserved through `Uri.IsBaseOf`, so URIs
whose scheme or host does not match the configured base URI are still
rejected as before

This ensures that only the actual path is evaluated for file extensions,
allowing query strings to contain dots without affecting navigation or
reload logic.

---

### Issues Fixed

Fixes #25689

Cover test result
<img width="477" alt="Screenshot 2025-05-16 at 22 54 41"
src="https://github.com/user-attachments/assets/55e5948b-17e6-4abd-9fad-d01172855c43"
/>


---

**Note:** @mattleibow  
The previous PR might have been truly cursed 😅 — I created a new branch,
rewrote the unit test project from scratch, and everything worked like a
charm this time.
No issues so far, and I'm optimistic GitHub Actions will behave too!
🧙‍♂️✨

Also, big thanks to @mattleibow for the support and guidance — your
insights helped me see things more clearly! 🙏
kubaflo pushed a commit that referenced this pull request Jul 10, 2026
…parameters (#29560)

<!-- Please let the below note in for people that find this PR -->
> [!NOTE]  
> Are you waiting for the changes in this PR to be merged?  
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->

### Description of Change

This PR fixes a bug in `BlazorWebView` where URLs containing dots (`.`)
in **query parameters** (e.g., `?weight=62.5`) could not be force
reloaded. The issue was caused by using `Path.HasExtension(uriString)`,
which mistakenly treated dots in query strings as if they were part of a
file extension.

---

#### ❌ Before

The original logic:

```csharp
if (Path.HasExtension(uriString))
    return false;
```

This evaluates the entire URI string — including query parameters —
which incorrectly caused `?value=62.5` to be treated as a file
reference, breaking reload behavior.

---

#### ✅ After

This PR introduces a safer and more accurate approach:

```csharp
if (Path.HasExtension(uri.AbsolutePath))
    return false;
```

Along with additional improvements:

* Validates input with `string.IsNullOrWhiteSpace`
* Uses `Uri.TryCreate` with `UriKind.Absolute` to safely parse the input
and reject relative or malformed URIs
* Scheme/host matching is preserved through `Uri.IsBaseOf`, so URIs
whose scheme or host does not match the configured base URI are still
rejected as before

This ensures that only the actual path is evaluated for file extensions,
allowing query strings to contain dots without affecting navigation or
reload logic.

---

### Issues Fixed

Fixes #25689

Cover test result
<img width="477" alt="Screenshot 2025-05-16 at 22 54 41"
src="https://github.com/user-attachments/assets/55e5948b-17e6-4abd-9fad-d01172855c43"
/>


---

**Note:** @mattleibow  
The previous PR might have been truly cursed 😅 — I created a new branch,
rewrote the unit test project from scratch, and everything worked like a
charm this time.
No issues so far, and I'm optimistic GitHub Actions will behave too!
🧙‍♂️✨

Also, big thanks to @mattleibow for the support and guidance — your
insights helped me see things more clearly! 🙏
kubaflo pushed a commit that referenced this pull request Jul 15, 2026
…parameters (#29560)

<!-- Please let the below note in for people that find this PR -->
> [!NOTE]  
> Are you waiting for the changes in this PR to be merged?  
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->

### Description of Change

This PR fixes a bug in `BlazorWebView` where URLs containing dots (`.`)
in **query parameters** (e.g., `?weight=62.5`) could not be force
reloaded. The issue was caused by using `Path.HasExtension(uriString)`,
which mistakenly treated dots in query strings as if they were part of a
file extension.

---

#### ❌ Before

The original logic:

```csharp
if (Path.HasExtension(uriString))
    return false;
```

This evaluates the entire URI string — including query parameters —
which incorrectly caused `?value=62.5` to be treated as a file
reference, breaking reload behavior.

---

#### ✅ After

This PR introduces a safer and more accurate approach:

```csharp
if (Path.HasExtension(uri.AbsolutePath))
    return false;
```

Along with additional improvements:

* Validates input with `string.IsNullOrWhiteSpace`
* Uses `Uri.TryCreate` with `UriKind.Absolute` to safely parse the input
and reject relative or malformed URIs
* Scheme/host matching is preserved through `Uri.IsBaseOf`, so URIs
whose scheme or host does not match the configured base URI are still
rejected as before

This ensures that only the actual path is evaluated for file extensions,
allowing query strings to contain dots without affecting navigation or
reload logic.

---

### Issues Fixed

Fixes #25689

Cover test result
<img width="477" alt="Screenshot 2025-05-16 at 22 54 41"
src="https://github.com/user-attachments/assets/55e5948b-17e6-4abd-9fad-d01172855c43"
/>


---

**Note:** @mattleibow  
The previous PR might have been truly cursed 😅 — I created a new branch,
rewrote the unit test project from scratch, and everything worked like a
charm this time.
No issues so far, and I'm optimistic GitHub Actions will behave too!
🧙‍♂️✨

Also, big thanks to @mattleibow for the support and guidance — your
insights helped me see things more clearly! 🙏
@github-actions github-actions Bot locked and limited conversation to collaborators Jul 22, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-blazor Blazor Hybrid / Desktop, BlazorWebView community ✨ Community Contribution s/agent-fix-pr-picked AI could not beat the PR fix - PR is the best among all candidates s/agent-reviewed PR was reviewed by AI agent workflow (full 4-phase review)

6 participants