Skip to content

Use OSPath.PathComparer in StaticWebAssetEndpoint.ToAssetFileDictionary#54749

Merged
jankratochvilcz merged 3 commits into
dotnet:mainfrom
jankratochvilcz:mt/fix-toassetfile-dictionary-comparer
Jun 18, 2026
Merged

Use OSPath.PathComparer in StaticWebAssetEndpoint.ToAssetFileDictionary#54749
jankratochvilcz merged 3 commits into
dotnet:mainfrom
jankratochvilcz:mt/fix-toassetfile-dictionary-comparer

Conversation

@jankratochvilcz

Copy link
Copy Markdown
Contributor

Fixes a latent path-comparer bug in StaticWebAssetEndpoint.ToAssetFileDictionary (src/StaticWebAssetsSdk/Tasks/Data/StaticWebAssetEndpoint.cs:178). The dictionary keys are absolute filesystem paths (endpoint.AssetFile, typically populated via MSBuild's %(FullPath) modifier), but the dictionary was constructed without a comparer — defaulting to ordinal case-sensitive on all platforms.

Impact

On Windows the filesystem is case-insensitive, so two endpoints whose AssetFile values differ only in casing (e.g. C:\Repo\WWWRoot\site.css vs c:\repo\wwwroot\site.css) land in separate buckets. This makes downstream lookups such as ApplyCompressionNegotiation's endpointsByAsset.TryGetValue(compressedAsset.Identity, …) silently miss when MSBuild round-trips path casing differently between producers (e.g. ResolveProjectReferences vs DefineStaticWebAssets), dropping the related-asset's endpoint from compression-negotiation processing.

Sibling SWA dictionaries pass Utils.OSPath.PathComparer for exactly this reason — see GeneratePackageAssetsManifestFile.cs:92 and UpdatePackageStaticWebAssets.cs:46.

Changes (TDD)

  1. Add failing test — adds StaticWebAssetEndpointToAssetFileDictionaryTest.GroupsEndpoints_ByPath_CaseInsensitively_OnWindows, a Windows-only PlatformSpecificFact that asserts case-divergent AssetFile values share a single dictionary entry. Fails on main (default ordinal comparer).
  2. Fix — pass OSPath.PathComparer (OrdinalIgnoreCase on Windows, Ordinal on Linux/macOS) to the Dictionary<string, List<StaticWebAssetEndpoint>> constructor.

The test is Windows-only because OSPath.PathComparer is OrdinalIgnoreCase only on Windows; on Linux/macOS it is StringComparer.Ordinal (matching the case-sensitive filesystem), which is observationally identical to the default Dictionary comparer.

Found during MT-safety audit of #54703.

@github-actions github-actions Bot added the Area-AspNetCore RazorSDK, BlazorWebAssemblySDK, StaticWebAssetsSDK label Jun 12, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Thanks for your PR, @jankratochvilcz.
To learn about the PR process and branching schedule of this repo, please take a look at the SDK PR Guide.

@jankratochvilcz jankratochvilcz marked this pull request as ready for review June 16, 2026 17:11
Copilot AI review requested due to automatic review settings June 16, 2026 17:11

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

Fixes a Windows path-casing bug in StaticWebAssetEndpoint.ToAssetFileDictionary by using the repo’s OS-aware path comparer (OSPath.PathComparer) when grouping endpoints by absolute filesystem path.

Changes:

  • Add a Windows-only unit test verifying that endpoints whose AssetFile differs only by casing are grouped into a single dictionary entry.
  • Construct the AssetFile dictionary with OSPath.PathComparer to match Windows’ case-insensitive filesystem behavior (while preserving ordinal behavior on Unix).

Reviewed changes

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

File Description
test/Microsoft.NET.Sdk.StaticWebAssets.Tests/StaticWebAssets/StaticWebAssetEndpointToAssetFileDictionaryTest.cs Adds a regression test covering case-insensitive grouping of AssetFile keys on Windows.
src/StaticWebAssetsSdk/Tasks/Data/StaticWebAssetEndpoint.cs Uses OSPath.PathComparer when building the AssetFile-keyed dictionary to avoid casing-related lookup misses on Windows.

@AlesProkop AlesProkop left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM

@jankratochvilcz jankratochvilcz enabled auto-merge (squash) June 17, 2026 08:12
@jankratochvilcz

Copy link
Copy Markdown
Contributor Author

/azp run dotnet-sdk-public-ci

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@jankratochvilcz

Copy link
Copy Markdown
Contributor Author

/azp run dotnet-sdk-public-ci

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

jankratochvilcz and others added 2 commits June 17, 2026 10:50
…sitively on Windows

StaticWebAssetEndpoint.ToAssetFileDictionary builds its keying dictionary
with the default ordinal comparer (StaticWebAssetEndpoint.cs:178). On
Windows the filesystem is case-insensitive, but two endpoints whose
AssetFile values differ only in casing (e.g. 'C:\Repo\WWWRoot\site.css'
vs 'c:\repo\wwwroot\site.css') currently land in separate buckets.

This makes downstream lookups such as ApplyCompressionNegotiation's
endpointsByAsset.TryGetValue(compressedAsset.Identity, ...) silently
miss when MSBuild round-trips path casing differently between producers
(ResolveProjectReferences vs DefineStaticWebAssets, etc.), dropping the
related-asset's endpoint from compression-negotiation processing.

Sibling SWA dictionaries (GeneratePackageAssetsManifestFile.cs:92,
UpdatePackageStaticWebAssets.cs:46) pass Utils.OSPath.PathComparer for
exactly this reason.

The test is Windows-only because OSPath.PathComparer is OrdinalIgnoreCase
only on Windows; on Linux/macOS it is StringComparer.Ordinal (matching
the case-sensitive filesystem), which is observationally identical to
the default Dictionary comparer.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Fixes the previously failing GroupsEndpoints_ByPath_CaseInsensitively_OnWindows
test by passing Utils.OSPath.PathComparer (OrdinalIgnoreCase on Windows,
Ordinal on Linux/macOS) to the keying dictionary so AssetFile path lookups
match the OS filesystem semantics, consistent with sibling SWA dictionaries
(GeneratePackageAssetsManifestFile.cs:92, UpdatePackageStaticWebAssets.cs:46).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jankratochvilcz jankratochvilcz force-pushed the mt/fix-toassetfile-dictionary-comparer branch from bd995ff to 004e4ab Compare June 17, 2026 08:50
@jankratochvilcz

Copy link
Copy Markdown
Contributor Author

/azp run dotnet-sdk-public-ci

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@jankratochvilcz

Copy link
Copy Markdown
Contributor Author

/azp run dotnet-sdk-public-ci

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@jankratochvilcz jankratochvilcz merged commit 183da97 into dotnet:main Jun 18, 2026
25 checks passed
@dotnet-milestone-bot dotnet-milestone-bot Bot added this to the 11.0-preview6 milestone Jun 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area-AspNetCore RazorSDK, BlazorWebAssemblySDK, StaticWebAssetsSDK

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants