[wasm] Move app-local vs runtime-pack conflict resolution into ComputeWasmBuildAssets (after .NET 12 branch)
- Dominant language
- C#
- Stars
- 18.3k
- Forks
- 5.6k
- PR merge metrics
- PR metrics pending
Description
> [!NOTE]
> This issue was drafted with the assistance of GitHub Copilot.
## Summary
Follow-up to #129334. That PR fixed a self-contained **browser-wasm CoreCLR** bug where a non-functional runtime-pack assembly stub shadows the functional app-local copy in the `_framework` bundle. The fix lives in a **CoreCLR-only** target and works, but the *root cause* is in the shared WebAssembly SDK bundling task. We should move the resolution down into `ComputeWasmBuildAssets` later, but **deliberately not now** (see "Why defer" below).
## Root cause
`Microsoft.NET.Sdk.WebAssembly.ComputeWasmBuildAssets` dedupes the webcil bundle candidates by **relative path, first-wins, version-blind**:
- `src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmBuildAssets.cs` ~L162:
```csharp
if (!uniqueRelativePaths.Add(relativePath))
{
// Skipping duplicate relative path ... (first candidate in iteration order wins)
continue;
}
```
- The candidate list is `@(WasmAssembliesToBundle)`, populated from `@(IntermediateAssembly)` + `@(ReferenceCopyLocalPaths)` (`.dll` only) in `Microsoft.NET.Sdk.WebAssembly.Browser.targets` (~L158-160). Whichever copy of a given file name appears first wins — regardless of `AssemblyVersion`.
For a self-contained CoreCLR app, `@(ReferenceCopyLocalPaths)` can contain **two** copies of the same assembly: the runtime-pack copy (under `$(MicrosoftNetCoreAppRuntimePackDir)`) and an app-local copy referenced out-of-band at a different version. The canonical case is `System.Runtime.Serialization.Formatters`: the shared framework ships a non-functional **8.1.0.0** stub while the app references the functional **11.0.0.0** build, so when the stub wins the dedup, `Assembly.Load(11.0.0.0)` fails at runtime with `FileNotFoundException`.
## Current workaround (shipped in #129334)
A new target `_CoreCLRPreferAppLocalAssembliesOverRuntimePack` in `src/mono/browser/build/BrowserWasmApp.CoreCLR.targets` runs before the bundle candidates are computed. It feeds the same-named runtime-pack/app-local pairs through the SDK's own `ResolvePackageFileConflicts` task (with `PreferredPackages` for exact publish parity) and prunes the losing copies from `@(ReferenceCopyLocalPaths)`, so the higher `AssemblyVersion` wins — exactly as a desktop self-contained publish would. This target is imported **only for `RuntimeFlavor == CoreCLR`**, so the common Mono path is untouched.
## Proposed proper fix (this issue)
Make the dedup in `ComputeWasmBuildAssets` (or a shared step feeding it) **version-aware**, so the same conflict resolution applies on the common Mono/CoreCLR path and both runtime flavors benefit. Once that lands, the `_CoreCLRPreferAppLocalAssembliesOverRuntimePack` band-aid in `BrowserWasmApp.CoreCLR.targets` can be removed.
## Why defer (do NOT do this now)
The `ComputeWasmBuildAssets` task and `WasmAssembliesToBundle` are on the **common Mono + CoreCLR build path**. Changing the dedup behavior there now risks regressing **.NET 11 Mono**, which currently does not hit this bug. To keep the .NET 11 blast radius minimal, #129334 intentionally scoped the fix to the CoreCLR-only targets file.
**Plan:** after the repo branches for **.NET 12**, move the resolution into `ComputeWasmBuildAssets` on `main`, validate both Mono and CoreCLR self-contained browser-wasm builds, and delete the CoreCLR-only workaround.
## Acceptance criteria
- [ ] Version-aware conflict resolution implemented in `ComputeWasmBuildAssets` (or a shared pre-bundle step) on the common path.
- [ ] Both Mono and CoreCLR self-contained browser-wasm builds bundle the higher-`AssemblyVersion` copy (verified with the `System.Runtime.Serialization.Formatters` 8.1.0.0-stub-vs-11.0.0.0 case).
- [ ] `_CoreCLRPreferAppLocalAssembliesOverRuntimePack` target and its guarded `UsingTask` removed from `src/mono/browser/build/BrowserWasmApp.CoreCLR.targets`.
- [ ] `System.Formats.Nrbf.Tests` (and any similarly affected suites) stay green on browser-wasm CoreCLR.
## References
- PR: #129334
- Workaround target: `src/mono/browser/build/BrowserWasmApp.CoreCLR.targets` (`_CoreCLRPreferAppLocalAssembliesOverRuntimePack`)
- Root-cause dedup: `src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmBuildAssets.cs` (`uniqueRelativePaths`, ~L162)
- Candidate population: `src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets` (~L158-160)
Contributor guide
Assessment
This issue has not been assessed yet.