Skip to content

Use OSPath.PathComparer in StaticWebAssetEndpoint.ToAssetFileDictionary#54749

Draft
jankratochvilcz wants to merge 2 commits into
dotnet:mainfrom
jankratochvilcz:mt/fix-toassetfile-dictionary-comparer
Draft

Use OSPath.PathComparer in StaticWebAssetEndpoint.ToAssetFileDictionary#54749
jankratochvilcz wants to merge 2 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.

jankratochvilcz and others added 2 commits June 12, 2026 18:25
…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>
@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.

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.

1 participant