Is there an existing issue for this?
Describe the bug
When OverrideHtmlAssetPlaceholders is set to true in a standalone Blazor WebAssembly project and index.html contains #[.{fingerprint}] placeholders (as documented for asset fingerprinting), hot reload via dotnet watch stops working. Code changes are detected and deltas are sent to the browser, but they are never applied — the page does not update.
Root cause
Setting OverrideHtmlAssetPlaceholders=true automatically sets BlazorFingerprintBlazorJs=true (in Microsoft.NET.Sdk.BlazorWebAssembly.6_0.targets, line 58). This causes blazor.webassembly.js to be fingerprinted with a content hash (e.g., blazor.webassembly.k8lfu09m0y.js).
During dotnet watch, each rebuild produces a different fingerprint hash, which changes the script filename in the processed index.html. The hot reload infrastructure (aspnetcore-browser-refresh.js) delivers deltas successfully over the WebSocket connection, but the delta application mechanism fails because the entry point script filename has changed between the initial page load and the rebuild.
The browser console shows deltas being received but never applied. No error is shown — hot reload silently fails.
Key finding from investigation
Through systematic isolation testing we confirmed:
| Configuration |
Hot reload |
OverrideHtmlAssetPlaceholders=true + #[.{fingerprint}] in index.html |
Broken |
OverrideHtmlAssetPlaceholders=true + plain blazor.webassembly.js in index.html |
Works |
OverrideHtmlAssetPlaceholders not set + plain blazor.webassembly.js |
Works |
The fingerprint placeholder in the HTML combined with JS fingerprinting is the specific combination that breaks hot reload. The OverrideHtmlAssetPlaceholders property alone (without the placeholder in HTML) does not cause the issue.
To Reproduce
-
Create a new Blazor WebAssembly Standalone app:
dotnet new blazorwasm -o BlazorHotReloadRepro
-
Add OverrideHtmlAssetPlaceholders to the .csproj:
<PropertyGroup>
<OverrideHtmlAssetPlaceholders>true</OverrideHtmlAssetPlaceholders>
</PropertyGroup>
-
Update wwwroot/index.html to use the fingerprint placeholder on the Blazor script tag:
<script src="_framework/blazor.webassembly#[.{fingerprint}].js"></script>
-
Run with dotnet watch:
-
Open the app in the browser, navigate to a page.
-
Make a visible change to a .razor file (e.g., change text in Home.razor).
-
Expected: The change appears in the browser via hot reload.
Actual: The change is never applied. The browser console shows hot reload deltas received but not applied.
-
To confirm the fix, add this to the .csproj:
<PropertyGroup>
<BlazorFingerprintBlazorJs Condition="'$(DOTNET_WATCH)' == '1'">false</BlazorFingerprintBlazorJs>
</PropertyGroup>
Restart dotnet watch — hot reload now works.
Suggested fix
The SDK should automatically set BlazorFingerprintBlazorJs=false when DOTNET_WATCH=1. This is consistent with how other watch-specific optimizations are already handled (e.g., the SDK disables documentation generation during watch builds).
In Microsoft.NET.Sdk.BlazorWebAssembly.6_0.targets, the existing line:
<BlazorFingerprintBlazorJs Condition="'$(BlazorFingerprintBlazorJs)' == '' and '$(OverrideHtmlAssetPlaceholders)' == 'true'">true</BlazorFingerprintBlazorJs>
Could be updated to:
<BlazorFingerprintBlazorJs Condition="'$(BlazorFingerprintBlazorJs)' == '' and '$(OverrideHtmlAssetPlaceholders)' == 'true' and '$(DOTNET_WATCH)' != '1'">true</BlazorFingerprintBlazorJs>
The OverrideHtmlAssetPlaceholders task with IncludeOnlyHardFingerprintedModules=false (used for build) correctly resolves #[.{fingerprint}] to an empty string when the asset isn't fingerprinted, so the HTML output is correct with just this property change.
Workaround
Add to Directory.Build.props (or individual .csproj):
<PropertyGroup>
<BlazorFingerprintBlazorJs Condition="'$(Configuration)' == 'Debug'">false</BlazorFingerprintBlazorJs>
</PropertyGroup>
This disables JS fingerprinting in Debug builds, preserving hot reload for both dotnet watch and Visual Studio. Release/Publish builds retain full fingerprinting.
Exceptions (if any)
No exceptions thrown. Hot reload silently fails — deltas are received but not applied.
.NET Version
10.0.100-preview.5 (also reproducible on 10.0.200-preview.0.26103.119)
Anything else?
- The
OverrideHtmlAssetPlaceholders task itself works correctly — when BlazorFingerprintBlazorJs=false, it resolves #[.{fingerprint}] to empty string, producing clean blazor.webassembly.js references.
- The issue also affects Visual Studio hot reload, not just
dotnet watch.
- Stale build artifacts can compound the issue — cleaning the artifacts directory is sometimes needed after toggling the property.
Is there an existing issue for this?
Describe the bug
When
OverrideHtmlAssetPlaceholdersis set totruein a standalone Blazor WebAssembly project andindex.htmlcontains#[.{fingerprint}]placeholders (as documented for asset fingerprinting), hot reload viadotnet watchstops working. Code changes are detected and deltas are sent to the browser, but they are never applied — the page does not update.Root cause
Setting
OverrideHtmlAssetPlaceholders=trueautomatically setsBlazorFingerprintBlazorJs=true(inMicrosoft.NET.Sdk.BlazorWebAssembly.6_0.targets, line 58). This causesblazor.webassembly.jsto be fingerprinted with a content hash (e.g.,blazor.webassembly.k8lfu09m0y.js).During
dotnet watch, each rebuild produces a different fingerprint hash, which changes the script filename in the processedindex.html. The hot reload infrastructure (aspnetcore-browser-refresh.js) delivers deltas successfully over the WebSocket connection, but the delta application mechanism fails because the entry point script filename has changed between the initial page load and the rebuild.The browser console shows deltas being received but never applied. No error is shown — hot reload silently fails.
Key finding from investigation
Through systematic isolation testing we confirmed:
OverrideHtmlAssetPlaceholders=true+#[.{fingerprint}]in index.htmlOverrideHtmlAssetPlaceholders=true+ plainblazor.webassembly.jsin index.htmlOverrideHtmlAssetPlaceholdersnot set + plainblazor.webassembly.jsThe fingerprint placeholder in the HTML combined with JS fingerprinting is the specific combination that breaks hot reload. The
OverrideHtmlAssetPlaceholdersproperty alone (without the placeholder in HTML) does not cause the issue.To Reproduce
Create a new Blazor WebAssembly Standalone app:
Add
OverrideHtmlAssetPlaceholdersto the.csproj:Update
wwwroot/index.htmlto use the fingerprint placeholder on the Blazor script tag:Run with
dotnet watch:Open the app in the browser, navigate to a page.
Make a visible change to a
.razorfile (e.g., change text inHome.razor).Expected: The change appears in the browser via hot reload.
Actual: The change is never applied. The browser console shows hot reload deltas received but not applied.
To confirm the fix, add this to the
.csproj:Restart
dotnet watch— hot reload now works.Suggested fix
The SDK should automatically set
BlazorFingerprintBlazorJs=falsewhenDOTNET_WATCH=1. This is consistent with how other watch-specific optimizations are already handled (e.g., the SDK disables documentation generation during watch builds).In
Microsoft.NET.Sdk.BlazorWebAssembly.6_0.targets, the existing line:Could be updated to:
The
OverrideHtmlAssetPlaceholderstask withIncludeOnlyHardFingerprintedModules=false(used for build) correctly resolves#[.{fingerprint}]to an empty string when the asset isn't fingerprinted, so the HTML output is correct with just this property change.Workaround
Add to
Directory.Build.props(or individual.csproj):This disables JS fingerprinting in Debug builds, preserving hot reload for both
dotnet watchand Visual Studio. Release/Publish builds retain full fingerprinting.Exceptions (if any)
No exceptions thrown. Hot reload silently fails — deltas are received but not applied.
.NET Version
10.0.100-preview.5 (also reproducible on 10.0.200-preview.0.26103.119)
Anything else?
OverrideHtmlAssetPlaceholderstask itself works correctly — whenBlazorFingerprintBlazorJs=false, it resolves#[.{fingerprint}]to empty string, producing cleanblazor.webassembly.jsreferences.dotnet watch.