Handle duplicate static web asset identities gracefully#53305
Open
ilonatommy wants to merge 4 commits intodotnet:mainfrom
Open
Handle duplicate static web asset identities gracefully#53305ilonatommy wants to merge 4 commits intodotnet:mainfrom
ilonatommy wants to merge 4 commits intodotnet:mainfrom
Conversation
Multiple StaticWebAssets MSBuild tasks crash with ArgumentException when candidate assets contain duplicate Identity keys. This happens when: - Hosted Blazor WASM projects reference multiple WASM client projects, causing dotnet.js.map from microsoft.netcore.app.runtime.mono.browser-wasm to appear multiple times via different dependency paths. - A Blazor Web App project references another Blazor Web App project, causing blazor.web.js from Microsoft.AspNetCore.App.Internal.Assets to appear twice. Fix all four code paths that build Identity-keyed dictionaries: - DiscoverPrecompressedAssets.Execute(): ToDictionary → ContainsKey loop - StaticWebAsset.ToAssetDictionary(): .Add → ContainsKey guard - GenerateStaticWebAssetsManifest: ToDictionary → ContainsKey loop - GenerateStaticWebAssetEndpointsManifest: ToDictionary → ContainsKey loop In all cases, the first occurrence is kept and subsequent duplicates are silently skipped. DiscoverPrecompressedAssets additionally logs skipped duplicates at Low message importance for diagnostics. Note: For the Blazor-references-Blazor scenario (dotnet#52089), this fix converts the unhandled ArgumentException crash into a proper diagnostic error (Conflicting assets with the same target path). The architectural fix for that scenario is tracked in dotnet#53135 (Framework SourceType), which prevents framework asset duplicates from being generated in the first place. Fixes dotnet#52089 Fixes dotnet#52647 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Contributor
|
Thanks for your PR, @@ilonatommy. |
Contributor
There was a problem hiding this comment.
Pull request overview
This PR prevents Static Web Assets MSBuild tasks from crashing when static web asset item groups contain duplicate Identity values, by changing Identity-keyed dictionary construction to skip subsequent duplicates.
Changes:
- Replaced
ToDictionary(...)calls withDictionary+ duplicate-guard loops in manifest generation tasks. - Updated
StaticWebAsset.ToAssetDictionary()to useOSPath.PathComparerand skip duplicate identities instead of throwing. - Updated
DiscoverPrecompressedAssetsto dedupe candidate assets by identity and emit a low-importance diagnostic when duplicates are skipped.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| src/StaticWebAssetsSdk/Tasks/GenerateStaticWebAssetsManifest.cs | Avoids ToDictionary duplicate-key crashes when filtering publish endpoints. |
| src/StaticWebAssetsSdk/Tasks/GenerateStaticWebAssetEndpointsManifest.cs | Avoids ToDictionary duplicate-key crashes when building the endpoints manifest asset map. |
| src/StaticWebAssetsSdk/Tasks/Data/StaticWebAsset.cs | Makes ToAssetDictionary() resilient to duplicate identities (and uses OS-specific path comparer). |
| src/StaticWebAssetsSdk/Tasks/Compression/DiscoverPrecompressedAssets.cs | Dedupes candidates by identity and logs when duplicates are skipped to prevent task failure. |
- Remove OSPath.PathComparer from ToAssetDictionary since StaticWebAsset.cs
is shared into BlazorWasmSdk which doesn't include OSPath.cs, causing
CS0103 build errors. The original code used the default comparer, so this
restores that behavior while keeping the duplicate-handling fix.
- Add DuplicateAssetIdentityHandlingTest with 6 targeted tests covering:
- ToAssetDictionary: first occurrence wins, no ArgumentException
- DiscoverPrecompressedAssets: duplicate candidates handled, compressed
pairs still discovered
- GenerateStaticWebAssetsManifest (Publish): no crash with duplicates
- GenerateStaticWebAssetEndpointsManifest: no crash with duplicates
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Address review feedback: all four duplicate-handling code paths now log at MessageImportance.Low when a duplicate identity is skipped, including the SourceId of both the kept and discarded assets for diagnostics. - ToAssetDictionary: accepts optional TaskLoggingHelper parameter; callers can pass Log to enable diagnostics without breaking existing signatures - GenerateStaticWebAssetsManifest: logs skipped duplicates in publish endpoint filtering - GenerateStaticWebAssetEndpointsManifest: logs skipped duplicates in manifest asset collection - DiscoverPrecompressedAssets: already had logging (unchanged) Also switched ContainsKey+indexer patterns to TryGetValue to satisfy CA1854 analyzer rule (avoid double dictionary lookup). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When duplicate asset identities have differing metadata (SourceId, RelativePath, or TargetPath), emit a build warning instead of a low-importance message. Identical duplicates (same file via multiple dependency paths) remain at MessageImportance.Low since they are harmless and expected in multi-WASM-project scenarios. This distinction helps surface cases where deduplication silently loses meaningful data (e.g., same file mapped to different target paths) while keeping the noise down for the common identical case. Updated tests to cover both paths: - Identical duplicates → Low message, no warning - Mismatched duplicates → Warning with metadata details Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Multiple
StaticWebAssetsMSBuild tasks crash withArgumentException: An item with the same key has already been addedwhen candidate assets contain duplicateIdentitykeys. This PR handles duplicates gracefully by keeping the first occurrence and skipping subsequent ones.What causes duplicates
Two known scenarios produce duplicate asset identities:
Hosted Blazor WASM projects referencing multiple WASM client projects —
dotnet.js.mapfrommicrosoft.netcore.app.runtime.mono.browser-wasmappears multiple times via different dependency paths. This blocks thedotnet/aspnetcoreCI codeflow PR (aspnetcore#65673).Blazor Web App referencing another Blazor Web App —
blazor.web.jsfromMicrosoft.AspNetCore.App.Internal.Assetsappears twice (repro: DanielSundberg/DiscoverPrecompressedAssets).What this PR fixes
All four code paths that build Identity-keyed dictionaries from static web asset items:
DiscoverPrecompressedAssets.csToDictionary→ContainsKeyloop with diagnostic logStaticWebAsset.ToAssetDictionary().Add→ContainsKeyguard (used by 5 other tasks)GenerateStaticWebAssetsManifest.csToDictionary→ContainsKeyloopGenerateStaticWebAssetEndpointsManifest.csToDictionary→ContainsKeyloopVerified locally
dotnet/aspnetcorecodeflow branch (darc-main-b867beb1-...) with SDK11.0.100-preview.3.26128.104HostedInAspNet.Serverbuilds successfully after patchingBlazorAppreferencingBlazorPlugin)DiscoverPrecompressedAssetscrash is eliminatedWhat this does NOT fix
For the Blazor-references-Blazor scenario (#52089), eliminating the
ArgumentExceptioncrash surfaces a different, pre-existing error:Conflicting assets with the same target path '_framework/blazor.server.js'This conflict occurs because the same framework asset arrives from two projects with different
SourceType(DiscoveredvsProject). The proper architectural fix for this is tracked in #53135 (FrameworkSourceType by @javiercn), which prevents framework asset duplicates from being generated in the first place.This PR and #53135 are complementary:
ToDictionarycrashes regardless of duplication sourceFixes #52089
Fixes #52647