From 535454feebf9e5e515c823caaf94495324cc0307 Mon Sep 17 00:00:00 2001 From: Larry Ewing Date: Fri, 27 Mar 2026 12:16:49 -0500 Subject: [PATCH 1/7] Add multi-client hosted build+publish test for WASM Framework materialization Add a proper BlazorMultiClientHosted test asset with two distinct WASM client projects (Client1, Client2) and a server project, each with unique content and StaticWebAssetBasePath. This replaces the synthetic test setup that cloned BlazorBasicTestApp and deleted files to avoid collisions. The test validates that Framework SourceType materialization produces per-project Identity values that work correctly through both the build and publish pipelines. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../wasm/Wasm.Build.Tests/Blazor/MiscTests.cs | 120 ++++++++---------- .../BrowserStructures/TestAsset.cs | 1 + .../BlazorMultiClientHosted/Client1/App.razor | 1 + .../Client1/Client1.csproj | 11 ++ .../Client1/Program.cs | 3 + .../BlazorMultiClientHosted/Client2/App.razor | 1 + .../Client2/Client2.csproj | 11 ++ .../Client2/Program.cs | 3 + .../BlazorMultiClientHosted/Server/Program.cs | 4 + .../Server/Server.csproj | 11 ++ 10 files changed, 98 insertions(+), 68 deletions(-) create mode 100644 src/mono/wasm/testassets/BlazorMultiClientHosted/Client1/App.razor create mode 100644 src/mono/wasm/testassets/BlazorMultiClientHosted/Client1/Client1.csproj create mode 100644 src/mono/wasm/testassets/BlazorMultiClientHosted/Client1/Program.cs create mode 100644 src/mono/wasm/testassets/BlazorMultiClientHosted/Client2/App.razor create mode 100644 src/mono/wasm/testassets/BlazorMultiClientHosted/Client2/Client2.csproj create mode 100644 src/mono/wasm/testassets/BlazorMultiClientHosted/Client2/Program.cs create mode 100644 src/mono/wasm/testassets/BlazorMultiClientHosted/Server/Program.cs create mode 100644 src/mono/wasm/testassets/BlazorMultiClientHosted/Server/Server.csproj diff --git a/src/mono/wasm/Wasm.Build.Tests/Blazor/MiscTests.cs b/src/mono/wasm/Wasm.Build.Tests/Blazor/MiscTests.cs index 7119f0ab36625f..d19043d2e50c61 100644 --- a/src/mono/wasm/Wasm.Build.Tests/Blazor/MiscTests.cs +++ b/src/mono/wasm/Wasm.Build.Tests/Blazor/MiscTests.cs @@ -103,79 +103,63 @@ public void BugRegression_60479_WithRazorClassLib() } [Theory] - [InlineData(Configuration.Debug)] - [InlineData(Configuration.Release)] - public void MultiClientHostedBuild(Configuration config) + [InlineData(Configuration.Debug, false)] + [InlineData(Configuration.Release, false)] + [InlineData(Configuration.Debug, true)] + [InlineData(Configuration.Release, true)] + public void MultiClientHostedBuildAndPublish(Configuration config, bool publish) { - // Test that two Blazor WASM client projects can be hosted by a single server project - // without duplicate static web asset Identity collisions. This validates the Framework - // SourceType materialization path that gives each client unique per-project Identity - // for shared runtime pack files. - ProjectInfo info = CopyTestAsset(config, aot: false, TestAsset.BlazorBasicTestApp, "multi_hosted"); - - // _projectDir is now .../App. Go up to the root and create a second client + server. - string rootDir = Path.GetDirectoryName(_projectDir)!; - string client1Dir = _projectDir; - string client2Dir = Path.Combine(rootDir, "App2"); - string serverDir = Path.Combine(rootDir, "Server"); - - // Duplicate App as App2 with a different StaticWebAssetBasePath - Utils.DirectoryCopy(client1Dir, client2Dir); - string client2Csproj = Path.Combine(client2Dir, "BlazorBasicTestApp.csproj"); - File.Move(client2Csproj, Path.Combine(client2Dir, "BlazorBasicTestApp2.csproj")); - client2Csproj = Path.Combine(client2Dir, "BlazorBasicTestApp2.csproj"); - - // Set different base paths so the two clients don't collide on routes - AddItemsPropertiesToProject(Path.Combine(client1Dir, "BlazorBasicTestApp.csproj"), - extraProperties: "client1"); - AddItemsPropertiesToProject(client2Csproj, - extraProperties: "client2BlazorBasicTestApp"); - - // Create a minimal server project that references both clients - Directory.CreateDirectory(serverDir); - string serverCsproj = Path.Combine(serverDir, "Server.csproj"); - File.WriteAllText(serverCsproj, $""" - - - {DefaultTargetFrameworkForBlazor} - enable - enable - - - - - - - """); - File.WriteAllText(Path.Combine(serverDir, "Program.cs"), """ - var builder = WebApplication.CreateBuilder(args); - var app = builder.Build(); - app.UseStaticFiles(); - app.Run(); - """); - - // Build the server project — this will transitively build both clients. - // Without Framework materialization, this would fail with duplicate Identity - // for shared runtime pack files (dotnet.native.js, ICU data, etc.) - string logPath = Path.Combine(s_buildEnv.LogRootPath, info.ProjectName, $"{info.ProjectName}-multi-hosted.binlog"); + // Test that two Blazor WASM client projects can be built/published by a single server + // project without duplicate static web asset Identity collisions. This validates the + // Framework SourceType materialization path that gives each client unique per-project + // Identity for shared runtime pack files. + string id = publish ? "multi_pub" : "multi_hosted"; + CopyTestAsset(config, aot: false, TestAsset.BlazorMultiClientHosted, id); + + string serverDir = _projectDir; + string rootDir = Path.GetDirectoryName(serverDir)!; + string client1Dir = Path.Combine(rootDir, "Client1"); + string client2Dir = Path.Combine(rootDir, "Client2"); + + string command = publish ? "publish" : "build"; + string logDir = Path.Combine(s_buildEnv.LogRootPath, id); + Directory.CreateDirectory(logDir); + string logPath = Path.Combine(logDir, $"{id}-{config}-{command}.binlog"); using ToolCommand cmd = new DotNetCommand(s_buildEnv, _testOutput) .WithWorkingDirectory(serverDir); - CommandResult result = cmd + _ = cmd .WithEnvironmentVariable("NUGET_PACKAGES", _nugetPackagesDir) - .ExecuteWithCapturedOutput("build", $"-p:Configuration={config}", $"-bl:{logPath}") + .ExecuteWithCapturedOutput(command, $"-p:Configuration={config}", $"-bl:{logPath}") .EnsureSuccessful(); - // Verify both clients produced framework files in their own bin directories - string client1Framework = Path.Combine(client1Dir, "bin", config.ToString(), DefaultTargetFrameworkForBlazor, "wwwroot", "_framework"); - string client2Framework = Path.Combine(client2Dir, "bin", config.ToString(), DefaultTargetFrameworkForBlazor, "wwwroot", "_framework"); - - Assert.True(Directory.Exists(client1Framework), $"Client1 framework dir missing: {client1Framework}"); - Assert.True(Directory.Exists(client2Framework), $"Client2 framework dir missing: {client2Framework}"); - - // Both should have dotnet.js (verifies framework files were materialized per-client) - var client1Files = Directory.GetFiles(client1Framework); - var client2Files = Directory.GetFiles(client2Framework); - Assert.Contains(client1Files, f => Path.GetFileName(f).StartsWith("dotnet.") && f.EndsWith(".js")); - Assert.Contains(client2Files, f => Path.GetFileName(f).StartsWith("dotnet.") && f.EndsWith(".js")); + if (publish) + { + string publishDir = Path.Combine(serverDir, "bin", config.ToString(), DefaultTargetFrameworkForBlazor, "publish"); + string client1Framework = Path.Combine(publishDir, "wwwroot", "client1", "_framework"); + string client2Framework = Path.Combine(publishDir, "wwwroot", "client2", "_framework"); + + Assert.True(Directory.Exists(client1Framework), $"Client1 publish framework dir missing: {client1Framework}"); + Assert.True(Directory.Exists(client2Framework), $"Client2 publish framework dir missing: {client2Framework}"); + + var client1Files = Directory.GetFiles(client1Framework); + var client2Files = Directory.GetFiles(client2Framework); + Assert.Contains(client1Files, f => Path.GetFileName(f).StartsWith("dotnet.") && f.EndsWith(".js")); + Assert.Contains(client2Files, f => Path.GetFileName(f).StartsWith("dotnet.") && f.EndsWith(".js")); + Assert.Contains(client1Files, f => Path.GetFileName(f).Contains("dotnet.native") && f.EndsWith(".wasm")); + Assert.Contains(client2Files, f => Path.GetFileName(f).Contains("dotnet.native") && f.EndsWith(".wasm")); + } + else + { + string client1Framework = Path.Combine(client1Dir, "bin", config.ToString(), DefaultTargetFrameworkForBlazor, "wwwroot", "_framework"); + string client2Framework = Path.Combine(client2Dir, "bin", config.ToString(), DefaultTargetFrameworkForBlazor, "wwwroot", "_framework"); + + Assert.True(Directory.Exists(client1Framework), $"Client1 framework dir missing: {client1Framework}"); + Assert.True(Directory.Exists(client2Framework), $"Client2 framework dir missing: {client2Framework}"); + + var client1Files = Directory.GetFiles(client1Framework); + var client2Files = Directory.GetFiles(client2Framework); + Assert.Contains(client1Files, f => Path.GetFileName(f).StartsWith("dotnet.") && f.EndsWith(".js")); + Assert.Contains(client2Files, f => Path.GetFileName(f).StartsWith("dotnet.") && f.EndsWith(".js")); + } } } diff --git a/src/mono/wasm/Wasm.Build.Tests/BrowserStructures/TestAsset.cs b/src/mono/wasm/Wasm.Build.Tests/BrowserStructures/TestAsset.cs index 83bf2e674d1a39..9369f4b7442cd8 100644 --- a/src/mono/wasm/Wasm.Build.Tests/BrowserStructures/TestAsset.cs +++ b/src/mono/wasm/Wasm.Build.Tests/BrowserStructures/TestAsset.cs @@ -6,4 +6,5 @@ public class TestAsset public static readonly TestAsset BlazorBasicTestApp = new() { Name = "BlazorBasicTestApp", RunnableProjectSubPath = "App" }; public static readonly TestAsset LibraryModeTestApp = new() { Name = "LibraryMode" }; public static readonly TestAsset BlazorWebWasm = new() { Name = "BlazorWebWasm", RunnableProjectSubPath = "BlazorWebWasm" }; + public static readonly TestAsset BlazorMultiClientHosted = new() { Name = "BlazorMultiClientHosted", RunnableProjectSubPath = "Server" }; } diff --git a/src/mono/wasm/testassets/BlazorMultiClientHosted/Client1/App.razor b/src/mono/wasm/testassets/BlazorMultiClientHosted/Client1/App.razor new file mode 100644 index 00000000000000..62fe080f86b9e4 --- /dev/null +++ b/src/mono/wasm/testassets/BlazorMultiClientHosted/Client1/App.razor @@ -0,0 +1 @@ +

Client 1

diff --git a/src/mono/wasm/testassets/BlazorMultiClientHosted/Client1/Client1.csproj b/src/mono/wasm/testassets/BlazorMultiClientHosted/Client1/Client1.csproj new file mode 100644 index 00000000000000..3d3e73d591c799 --- /dev/null +++ b/src/mono/wasm/testassets/BlazorMultiClientHosted/Client1/Client1.csproj @@ -0,0 +1,11 @@ + + + $(TargetFramework) + client1 + enable + enable + + + + + diff --git a/src/mono/wasm/testassets/BlazorMultiClientHosted/Client1/Program.cs b/src/mono/wasm/testassets/BlazorMultiClientHosted/Client1/Program.cs new file mode 100644 index 00000000000000..2bab420617502b --- /dev/null +++ b/src/mono/wasm/testassets/BlazorMultiClientHosted/Client1/Program.cs @@ -0,0 +1,3 @@ +using Microsoft.AspNetCore.Components.WebAssembly.Hosting; +var builder = WebAssemblyHostBuilder.CreateDefault(args); +await builder.Build().RunAsync(); diff --git a/src/mono/wasm/testassets/BlazorMultiClientHosted/Client2/App.razor b/src/mono/wasm/testassets/BlazorMultiClientHosted/Client2/App.razor new file mode 100644 index 00000000000000..b92590ba042139 --- /dev/null +++ b/src/mono/wasm/testassets/BlazorMultiClientHosted/Client2/App.razor @@ -0,0 +1 @@ +

Client 2

diff --git a/src/mono/wasm/testassets/BlazorMultiClientHosted/Client2/Client2.csproj b/src/mono/wasm/testassets/BlazorMultiClientHosted/Client2/Client2.csproj new file mode 100644 index 00000000000000..9d7006b533e3da --- /dev/null +++ b/src/mono/wasm/testassets/BlazorMultiClientHosted/Client2/Client2.csproj @@ -0,0 +1,11 @@ + + + $(TargetFramework) + client2 + enable + enable + + + + + diff --git a/src/mono/wasm/testassets/BlazorMultiClientHosted/Client2/Program.cs b/src/mono/wasm/testassets/BlazorMultiClientHosted/Client2/Program.cs new file mode 100644 index 00000000000000..2bab420617502b --- /dev/null +++ b/src/mono/wasm/testassets/BlazorMultiClientHosted/Client2/Program.cs @@ -0,0 +1,3 @@ +using Microsoft.AspNetCore.Components.WebAssembly.Hosting; +var builder = WebAssemblyHostBuilder.CreateDefault(args); +await builder.Build().RunAsync(); diff --git a/src/mono/wasm/testassets/BlazorMultiClientHosted/Server/Program.cs b/src/mono/wasm/testassets/BlazorMultiClientHosted/Server/Program.cs new file mode 100644 index 00000000000000..9a0fcc0d065fd3 --- /dev/null +++ b/src/mono/wasm/testassets/BlazorMultiClientHosted/Server/Program.cs @@ -0,0 +1,4 @@ +var builder = WebApplication.CreateBuilder(args); +var app = builder.Build(); +app.UseStaticFiles(); +app.Run(); diff --git a/src/mono/wasm/testassets/BlazorMultiClientHosted/Server/Server.csproj b/src/mono/wasm/testassets/BlazorMultiClientHosted/Server/Server.csproj new file mode 100644 index 00000000000000..35806b51693b69 --- /dev/null +++ b/src/mono/wasm/testassets/BlazorMultiClientHosted/Server/Server.csproj @@ -0,0 +1,11 @@ + + + $(TargetFramework) + enable + enable + + + + + + From 2fae9ba0567f084b2a7c29dd9c98260637de40d3 Mon Sep 17 00:00:00 2001 From: Larry Ewing Date: Sun, 29 Mar 2026 19:30:38 -0500 Subject: [PATCH 2/7] Rename Server.csproj to BlazorMultiClientHosted.csproj to match test asset name The test harness expects a .csproj named after the TestAsset.Name property ('BlazorMultiClientHosted') in the RunnableProjectSubPath directory. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Server/{Server.csproj => BlazorMultiClientHosted.csproj} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/mono/wasm/testassets/BlazorMultiClientHosted/Server/{Server.csproj => BlazorMultiClientHosted.csproj} (100%) diff --git a/src/mono/wasm/testassets/BlazorMultiClientHosted/Server/Server.csproj b/src/mono/wasm/testassets/BlazorMultiClientHosted/Server/BlazorMultiClientHosted.csproj similarity index 100% rename from src/mono/wasm/testassets/BlazorMultiClientHosted/Server/Server.csproj rename to src/mono/wasm/testassets/BlazorMultiClientHosted/Server/BlazorMultiClientHosted.csproj From d9d942685a0ba4b7daf476a3c12759109948288f Mon Sep 17 00:00:00 2001 From: Larry Ewing Date: Mon, 30 Mar 2026 10:35:35 -0500 Subject: [PATCH 3/7] Hardcode TFM and package versions in BlazorMultiClientHosted test assets Match the pattern used by all other wasm test assets (BlazorBasicTestApp, BlazorWebWasm, etc.) which hardcode net11.0 and explicit package versions rather than relying on undefined MSBuild properties. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../testassets/BlazorMultiClientHosted/Client1/Client1.csproj | 4 ++-- .../testassets/BlazorMultiClientHosted/Client2/Client2.csproj | 4 ++-- .../Server/BlazorMultiClientHosted.csproj | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/mono/wasm/testassets/BlazorMultiClientHosted/Client1/Client1.csproj b/src/mono/wasm/testassets/BlazorMultiClientHosted/Client1/Client1.csproj index 3d3e73d591c799..cc2037ddfabaa7 100644 --- a/src/mono/wasm/testassets/BlazorMultiClientHosted/Client1/Client1.csproj +++ b/src/mono/wasm/testassets/BlazorMultiClientHosted/Client1/Client1.csproj @@ -1,11 +1,11 @@ - $(TargetFramework) + net11.0 client1 enable enable - + diff --git a/src/mono/wasm/testassets/BlazorMultiClientHosted/Client2/Client2.csproj b/src/mono/wasm/testassets/BlazorMultiClientHosted/Client2/Client2.csproj index 9d7006b533e3da..8f0edfc6a763f0 100644 --- a/src/mono/wasm/testassets/BlazorMultiClientHosted/Client2/Client2.csproj +++ b/src/mono/wasm/testassets/BlazorMultiClientHosted/Client2/Client2.csproj @@ -1,11 +1,11 @@ - $(TargetFramework) + net11.0 client2 enable enable - + diff --git a/src/mono/wasm/testassets/BlazorMultiClientHosted/Server/BlazorMultiClientHosted.csproj b/src/mono/wasm/testassets/BlazorMultiClientHosted/Server/BlazorMultiClientHosted.csproj index 35806b51693b69..b95f195788d5a0 100644 --- a/src/mono/wasm/testassets/BlazorMultiClientHosted/Server/BlazorMultiClientHosted.csproj +++ b/src/mono/wasm/testassets/BlazorMultiClientHosted/Server/BlazorMultiClientHosted.csproj @@ -1,6 +1,6 @@ - $(TargetFramework) + net11.0 enable enable From b8b53862ef01be7baffe1334848280b5bcfeb7e5 Mon Sep 17 00:00:00 2001 From: Larry Ewing Date: Mon, 30 Mar 2026 15:25:18 -0500 Subject: [PATCH 4/7] Add publish-time Framework materialization for WASM pass-through assets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The build path captures PassThroughCandidates from ConvertDllsToWebcil and routes them through DefineStaticWebAssets(SourceType=Framework) + UpdatePackageStaticWebAssets for per-project materialization. The publish path was missing this — pass-through assets (like HotReload dlls) kept their raw SDK path, causing duplicate Identity crashes in ApplyCompressionNegotiation for multi-client hosted Blazor WASM publish. Mirror the build-time pattern: capture PassThroughCandidates, remove them from webcil candidates, define as Framework assets, and materialize to per-project paths. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- ...rosoft.NET.Sdk.WebAssembly.Browser.targets | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets b/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets index 171388aee4da54..ad542cedc7b2a4 100644 --- a/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets +++ b/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets @@ -787,9 +787,59 @@ Copyright (c) .NET Foundation. All rights reserved. + + + + <_NewWebcilPublishStaticWebAssetsCandidates Remove="@(_WasmPublishFrameworkCandidates)" /> + <_WasmPublishFrameworkCandidates Update="@(_WasmPublishFrameworkCandidates)" ContentRoot="%(RootDir)%(Directory)" /> + + + + + + + + + + + + + <_WasmMaterializedPublishFrameworkAssets Update="@(_WasmMaterializedPublishFrameworkAssets)" + AssetMode="All" CopyToPublishDirectory="PreserveNewest" /> + + + + + + + From 49ad4beb1101378f0b5b2f2ee93f40c28a17ee51 Mon Sep 17 00:00:00 2001 From: Larry Ewing Date: Mon, 30 Mar 2026 16:24:04 -0500 Subject: [PATCH 5/7] Use _logPath for binlog output to match other tests CopyTestAsset already initializes _logPath via InitPaths, which creates the per-test log directory under s_buildEnv.LogRootPath. Use it instead of manually creating a separate directory. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/mono/wasm/Wasm.Build.Tests/Blazor/MiscTests.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/mono/wasm/Wasm.Build.Tests/Blazor/MiscTests.cs b/src/mono/wasm/Wasm.Build.Tests/Blazor/MiscTests.cs index d19043d2e50c61..8f0b6d3d7feee6 100644 --- a/src/mono/wasm/Wasm.Build.Tests/Blazor/MiscTests.cs +++ b/src/mono/wasm/Wasm.Build.Tests/Blazor/MiscTests.cs @@ -122,9 +122,7 @@ public void MultiClientHostedBuildAndPublish(Configuration config, bool publish) string client2Dir = Path.Combine(rootDir, "Client2"); string command = publish ? "publish" : "build"; - string logDir = Path.Combine(s_buildEnv.LogRootPath, id); - Directory.CreateDirectory(logDir); - string logPath = Path.Combine(logDir, $"{id}-{config}-{command}.binlog"); + string logPath = Path.Combine(_logPath, $"{id}-{config}-{command}.binlog"); using ToolCommand cmd = new DotNetCommand(s_buildEnv, _testOutput) .WithWorkingDirectory(serverDir); _ = cmd From 13ba188437ad1646db0eebc6cb4fe2010a3bea42 Mon Sep 17 00:00:00 2001 From: Larry Ewing Date: Mon, 30 Mar 2026 19:53:42 -0500 Subject: [PATCH 6/7] Revert "Add publish-time Framework materialization for WASM pass-through assets" This reverts commit b8b53862ef01be7baffe1334848280b5bcfeb7e5. --- ...rosoft.NET.Sdk.WebAssembly.Browser.targets | 50 ------------------- 1 file changed, 50 deletions(-) diff --git a/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets b/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets index ad542cedc7b2a4..171388aee4da54 100644 --- a/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets +++ b/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets @@ -787,59 +787,9 @@ Copyright (c) .NET Foundation. All rights reserved. - - - - <_NewWebcilPublishStaticWebAssetsCandidates Remove="@(_WasmPublishFrameworkCandidates)" /> - <_WasmPublishFrameworkCandidates Update="@(_WasmPublishFrameworkCandidates)" ContentRoot="%(RootDir)%(Directory)" /> - - - - - - - - - - - - - <_WasmMaterializedPublishFrameworkAssets Update="@(_WasmMaterializedPublishFrameworkAssets)" - AssetMode="All" CopyToPublishDirectory="PreserveNewest" /> - - - - - - - From b838db29ba5d59e2edf171f59703483e86b52790 Mon Sep 17 00:00:00 2001 From: Larry Ewing Date: Mon, 30 Mar 2026 19:53:56 -0500 Subject: [PATCH 7/7] Filter CopyToPublishDirectory=Never from publish asset resolution Filter ResolvedFileToPublish items with CopyToPublishDirectory=Never when building _WasmResolvedFilesToPublish. This is defense-in-depth for multi-client hosted publish scenarios where build-only assets (like the HotReload dll) could leak into ComputeWasmPublishAssets. The primary fix for the HotReload duplicate is in the SDK's Sdk.targets where _WasmImplicitlyReferenceHotReload should copy the dll to intermediate (matching the pattern already used for the .js module). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../build/Microsoft.NET.Sdk.WebAssembly.Browser.targets | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets b/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets index 171388aee4da54..74e652d5c9bef5 100644 --- a/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets +++ b/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets @@ -751,7 +751,13 @@ Copyright (c) .NET Foundation. All rights reserved. - <_WasmResolvedFilesToPublish Include="@(ResolvedFileToPublish)" /> + + <_WasmResolvedFilesToPublish Include="@(ResolvedFileToPublish)" + Condition="'%(ResolvedFileToPublish.CopyToPublishDirectory)' != 'Never'" />