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 707ce66956448e..01d02adbc23fc8 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
@@ -349,7 +349,6 @@ Copyright (c) .NET Foundation. All rights reserved.
<_WasmBuildWebCilPath>$([MSBuild]::NormalizeDirectory($(IntermediateOutputPath), 'webcil'))
<_WasmBuildTmpWebCilPath>$([MSBuild]::NormalizeDirectory($(IntermediateOutputPath), 'tmp-webcil'))
- <_WasmBuildOuputPath>$([MSBuild]::NormalizeDirectory('$(OutputPath)', 'wwwroot'))
@@ -358,6 +357,8 @@ Copyright (c) .NET Foundation. All rights reserved.
+
+ <_WebCilAssetsCandidates Update="@(_WebCilAssetsCandidates)" ContentRoot="%(RootDir)%(Directory)" />
<_WasmFingerprintPatterns Include="WasmFiles" Pattern="*.wasm" Expression="#[.{fingerprint}]!" />
<_WasmFingerprintPatterns Include="DllFiles" Pattern="*.dll" Expression="#[.{fingerprint}]!" />
<_WasmFingerprintPatterns Include="DatFiles" Pattern="*.dat" Expression="#[.{fingerprint}]!" />
@@ -372,7 +373,6 @@ Copyright (c) .NET Foundation. All rights reserved.
AssetRole="Primary"
CopyToOutputDirectory="PreserveNewest"
CopyToPublishDirectory="Never"
- ContentRoot="$(_WasmBuildOuputPath)"
FingerprintCandidates="$(_WasmFingerprintAssets)"
FingerprintPatterns="@(FingerprintPatterns);@(_WasmFingerprintPatterns)"
BasePath="$(StaticWebAssetBasePath)"
@@ -518,7 +518,7 @@ Copyright (c) .NET Foundation. All rights reserved.
AssetTraitValue="manifest"
CopyToOutputDirectory="PreserveNewest"
CopyToPublishDirectory="Never"
- ContentRoot="$(OutDir)wwwroot"
+ ContentRoot="$(IntermediateOutputPath)"
BasePath="$(StaticWebAssetBasePath)"
>
@@ -584,18 +584,10 @@ Copyright (c) .NET Foundation. All rights reserved.
-
- <_WasmBootConfigFileNameWithoutExtension>$([System.IO.Path]::GetFileNameWithoutExtension('$(_WasmBootConfigFileName)'))
- <_WasmBootConfigFileExtension>$([System.IO.Path]::GetExtension('$(_WasmBootConfigFileName)'))
-
-
- <_WasmPreloadBuildScriptAsset Include="@(StaticWebAsset)" Condition="'$(_WasmFingerprintAssets)' == 'true' and '$(_WasmFingerprintBootConfig)' == 'true' and '%(AssetKind)' != 'Publish' and '%(FileName)%(Extension)' == '$(_WasmBootConfigFileNameWithoutExtension).%(Fingerprint)$(_WasmBootConfigFileExtension)'" />
- <_WasmPreloadBuildScriptAsset Include="@(StaticWebAsset)" Condition="('$(_WasmFingerprintAssets)' != 'true' or '$(_WasmFingerprintBootConfig)' != 'true') and '%(AssetKind)' != 'Publish' and '%(FileName)%(Extension)' == '$(_WasmBootConfigFileName)'" />
-
@@ -614,13 +606,10 @@ Copyright (c) .NET Foundation. All rights reserved.
-
- <_WasmPreloadPublishScriptAsset Include="@(StaticWebAsset)" Condition="'%(AssetKind)' != 'Build' and '%(FileName)%(Extension)' == '$(_WasmPublishBootConfigFileName)'" />
-
@@ -729,6 +718,18 @@ Copyright (c) .NET Foundation. All rights reserved.
<_NewWebCilPublishStaticWebAssetsCandidatesNoMetadata
Include="@(_NewWebCilPublishStaticWebAssetsCandidates)"
RemoveMetadata="Integrity;Fingerprint" />
+
+ <_NewWebCilPublishStaticWebAssetsCandidatesNoMetadata Update="@(_NewWebCilPublishStaticWebAssetsCandidatesNoMetadata)" ContentRoot="%(RootDir)%(Directory)" />
+ <_PromotedWasmPublishStaticWebAssets Update="@(_PromotedWasmPublishStaticWebAssets)" ContentRoot="%(RootDir)%(Directory)" Fingerprint="" Integrity="" />
+
+ <_PromotedWasmPublishStaticWebAssets
+ Update="@(_PromotedWasmPublishStaticWebAssets)"
+ Condition="'%(_PromotedWasmPublishStaticWebAssets.AssetTraitName)' == 'Culture'"
+ AssetRole="Primary"
+ RelatedAsset="" />
diff --git a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmPublishAssets.cs b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmPublishAssets.cs
index 69205e6f3b982f..dfa1bce752144f 100644
--- a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmPublishAssets.cs
+++ b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmPublishAssets.cs
@@ -332,23 +332,11 @@ static bool IsDotNetWasm(string key)
private TaskItem CreatePromotedAsset(ITaskItem asset)
{
- string newAssetItemSpec = asset.ItemSpec;
- string newAssetRelativePath = asset.GetMetadata("RelativePath");
-
- if (FingerprintAssets)
- {
- string assetDirectory = Path.GetDirectoryName(asset.ItemSpec);
- string assetFileNameToFingerprint = Path.GetFileName(newAssetRelativePath);
- string fingerprint = asset.GetMetadata("Fingerprint");
- string newAssetFingerprintedFileName = assetFileNameToFingerprint.Replace("#[.{fingerprint}]!", $".{fingerprint}");
- if (newAssetFingerprintedFileName != assetFileNameToFingerprint)
- {
- newAssetItemSpec = $"{assetDirectory}/{newAssetFingerprintedFileName}";
- }
- }
-
- var newAsset = new TaskItem(newAssetItemSpec, asset.CloneCustomMetadata());
- newAsset.SetMetadata("RelativePath", newAssetRelativePath);
+ // Keep ItemSpec pointing to the actual file on disk.
+ // DefineStaticWebAssets will resolve fingerprint placeholders in RelativePath
+ // and compute Fingerprint/Integrity from the real file.
+ var newAsset = new TaskItem(asset.ItemSpec, asset.CloneCustomMetadata());
+ newAsset.SetMetadata("RelativePath", asset.GetMetadata("RelativePath"));
ApplyPublishProperties(newAsset);
return newAsset;
@@ -446,6 +434,10 @@ private void ComputeUpdatedAssemblies(
// when the original assembly they depend on has been linked out.
var assetsToUpdate = new Dictionary();
var linkedAssets = new Dictionary();
+ // Secondary lookup by normalized filename for satellite matching.
+ // RelatedAsset may use a different base path (e.g., OutputPath/wwwroot)
+ // than the asset's build-time Identity (e.g., IntermediateOutputPath/webcil).
+ var assetsToUpdateByFileName = new Dictionary(StringComparer.OrdinalIgnoreCase);
foreach (var kvp in assemblyAssets)
{
@@ -459,6 +451,8 @@ private void ComputeUpdatedAssemblies(
{
// We found the assembly, so it'll have to be updated.
assetsToUpdate.Add(assetToUpdateItemSpec, asset);
+ if (!assetsToUpdateByFileName.ContainsKey(fileName))
+ assetsToUpdateByFileName[fileName] = assetToUpdateItemSpec;
filesToRemove.Add(existing);
if (!string.Equals(asset.ItemSpec, existing.GetMetadata("FullPath"), StringComparison.Ordinal))
{
@@ -477,6 +471,18 @@ private void ComputeUpdatedAssemblies(
var satelliteAssembly = kvp.Value;
var relatedAsset = satelliteAssembly.GetMetadata("RelatedAsset");
+ // Try exact match first, then fall back to filename-based lookup.
+ // Normalize to .dll when webcil is enabled since assetsToUpdateByFileName
+ // keys are normalized to .dll (line 448) but RelatedAsset paths use .wasm.
+ var relatedAssetFileName = Path.GetFileName(relatedAsset);
+ if (IsWebCilEnabled)
+ relatedAssetFileName = Path.ChangeExtension(relatedAssetFileName, ".dll");
+ if (!assetsToUpdate.ContainsKey(relatedAsset)
+ && assetsToUpdateByFileName.TryGetValue(relatedAssetFileName, out var matchedKey))
+ {
+ relatedAsset = matchedKey;
+ }
+
if (assetsToUpdate.ContainsKey(relatedAsset))
{
assetsToUpdate.Add(satelliteAssembly.ItemSpec, satelliteAssembly);
@@ -590,9 +596,24 @@ private List ProcessCompressedAssets(
private static void UpdateRelatedAssetProperty(ITaskItem asset, TaskItem newAsset, Dictionary updatedAssetsMap)
{
- if (!updatedAssetsMap.TryGetValue(asset.GetMetadata("RelatedAsset"), out var updatedRelatedAsset))
+ var relatedAsset = asset.GetMetadata("RelatedAsset");
+ if (!updatedAssetsMap.TryGetValue(relatedAsset, out var updatedRelatedAsset))
{
- throw new InvalidOperationException("Related asset not found.");
+ // Fall back to filename matching when RelatedAsset uses a different base path
+ // than the asset's build-time Identity (e.g., OutputPath/wwwroot vs obj/webcil).
+ var relatedBaseName = Path.GetFileNameWithoutExtension(relatedAsset);
+ foreach (var kvp in updatedAssetsMap)
+ {
+ if (string.Equals(Path.GetFileNameWithoutExtension(kvp.Key), relatedBaseName, StringComparison.OrdinalIgnoreCase))
+ {
+ updatedRelatedAsset = kvp.Value;
+ break;
+ }
+ }
+ if (updatedRelatedAsset == null)
+ {
+ throw new InvalidOperationException("Related asset not found.");
+ }
}
newAsset.SetMetadata("RelatedAsset", updatedRelatedAsset.ItemSpec);