Fix Test Tool v2 Blazor UI non-interactive on .NET 10 (static assets 404)#2492
Draft
GarrettBeatty wants to merge 4 commits into
Draft
Fix Test Tool v2 Blazor UI non-interactive on .NET 10 (static assets 404)#2492GarrettBeatty wants to merge 4 commits into
GarrettBeatty wants to merge 4 commits into
Conversation
…404) On .NET 9+ the Blazor framework files (_framework/blazor.web.js) and the scoped-CSS bundle are served through the endpoint-routing MapStaticAssets API backed by the *.staticwebassets.endpoints.json manifest, not the classic static-files middleware. The tool only registered a wwwroot-only UseStaticFiles provider, so on net10 those assets returned 404, window.Blazor was never defined, no interactive server circuit was established, and the whole UI rendered statically (buttons/@onclick/@Bind non-functional). Add a NET9_0_OR_GREATER-guarded app.MapStaticAssets() so net9+ serves the framework + scoped assets via the endpoints manifest while net8.0 keeps its existing path. Also disable the build-manifest dev-time runtime-patching handler (ReloadStaticAssetsAtRuntime=false), which otherwise probes those assets through the physical wwwroot provider and threw FileNotFoundException (HTTP 500) for _framework/* under dotnet run/build.
…esponses) The previous fix made _framework/blazor.web.js return HTTP 200 but with an empty (0-byte) body, so window.Blazor was still never defined and the UI stayed non-interactive. Two root causes, both fixed here: 1. MapStaticAssets serves asset bytes from IWebHostEnvironment.WebRootFileProvider. Under dotnet run the framework files live in the NuGet cache and are mapped in via *.staticwebassets.runtime.json, but ASP.NET Core only composes that manifest into the web root automatically in the Development environment. The tool runs as Production by default, so the web root was a bare wwwroot provider and the invoker caught FileNotFoundException and returned an empty 200. Fixed by calling builder.WebHost.UseStaticWebAssets(), which composes the manifest regardless of environment (and is a harmless no-op for the installed tool, where the framework files are published directly into wwwroot). 2. As an installed global tool the process launches from an arbitrary working directory, and the default content root (hence WebRootFileProvider = contentRoot/wwwroot) followed the cwd, so MapStaticAssets looked in a nonexistent wwwroot and returned empty 200s for every asset. Fixed by pinning ContentRootPath to AppContext.BaseDirectory. Replaces the earlier ReloadStaticAssetsAtRuntime=false workaround, which only suppressed the dev hot-reload 500 but left MapStaticAssets serving 0 bytes. Verified on net10 with byte counts and a real browser (Playwright window.Blazor): - dotnet run: blazor.web.js=200575 bytes, styles.css=2024, bootstrap=232808; window.Blazor=true on / and /documentation. - installed global tool launched from a foreign cwd: same byte counts; window.Blazor=true on / and /documentation. net8 still builds and stays interactive (window.Blazor=true).
TestToolProcess.Startup is invoked directly by unit tests (RuntimeApiTests, RunCommandTests) inside the xUnit test host. MapStaticAssets() throws InvalidOperationException when the *.staticwebassets.endpoints.json manifest is absent, and the manifest is named after the entry assembly — under the test host that's 'testhost', so the tool's manifest isn't present and every test that calls Startup failed on net10 (net8 was unaffected as it doesn't call MapStaticAssets). Guard the call so it only maps static assets when the expected manifest exists: the running tool has it (assets serve, UI is interactive); the test host does not (skipped, and those tests only exercise the Runtime API). Verified: the previously-failing net10 tests pass, and the real tool still serves _framework/blazor.web.js with real bytes.
Contributor
There was a problem hiding this comment.
Pull request overview
Fixes AWS Lambda Test Tool v2’s Blazor UI becoming non-interactive on .NET 9+/net10 by ensuring the .NET 9+ static web assets endpoint pipeline can actually locate and serve framework/scoped-CSS assets regardless of launch working directory and hosting environment.
Changes:
- Pins ASP.NET Core content root to
AppContext.BaseDirectorysoWebRootFileProviderresolveswwwrootcorrectly when the tool is launched from an arbitrary cwd (global tool scenario). - On
NET9_0_OR_GREATER, composes static web assets (UseStaticWebAssets) and maps endpoint-based static assets (MapStaticAssets) with a guard to avoid failures when running under a test host. - Adds an Autover patch changelog entry documenting the fix.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| Tools/LambdaTestTool-v2/src/Amazon.Lambda.TestTool/Processes/TestToolProcess.cs | Adjusts hosting options and .NET 9+ static web assets setup so Blazor framework/scoped CSS assets resolve and the UI becomes interactive again. |
| .autover/changes/156dd8b1-1af2-45fc-b051-b94dc51fc56f.json | Records a patch-level changelog entry for the .NET 9+/net10 static assets/Blazor interactivity fix. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
GarrettBeatty
marked this pull request as ready for review
July 23, 2026 13:37
GarrettBeatty
marked this pull request as draft
July 23, 2026 19:44
The Blazor web UI's static-asset serving was only fully fixed for .NET 9+. On .NET 8, running from a build output (dotnet run / dotnet build) left Razor class library content — notably BlazorMonaco's _content/BlazorMonaco/** editor assets — returning 404, so the request/response code editor never initialized and selecting an example request could not populate the input. Root cause: those RCL assets are not physically under wwwroot in a build output; they are surfaced through the static-web-assets runtime manifest. UseStaticWebAssets() (which composes that manifest into the WebRootFileProvider) was guarded to net9+, and the classic UseStaticFiles middleware was pinned to an explicit bare-wwwroot provider that never reads the composed manifest. On net9+ MapStaticAssets reads the WebRootFileProvider so it worked there; net8 had no such reader. Fix: - Compose the static-web-assets manifest on all target frameworks (make UseStaticWebAssets() unconditional). - On .NET 8, add a second UseStaticFiles pass over the WebRootFileProvider so manifest-mapped _content/** assets resolve. For an installed global tool the WebRootFileProvider is the same wwwroot (assets published there directly), so it is a harmless second lookup. Verified across the full matrix — .NET 8/.NET 10 x Development/Production x dotnet-run/installed-tool (8/8 serve _framework, _content/BlazorMonaco, and app.css with non-zero bytes).
GarrettBeatty
added a commit
that referenced
this pull request
Jul 23, 2026
Replace the Test Tool durable emulator's hand-maintained fork of the checkpoint state machine and operation store with the shared Amazon.Lambda.DurableExecution.LocalEmulation package, so it cannot drift from the durable-execution testing package. - Delete the forked CheckpointProcessor and InMemoryOperationStore. - Add WireOperationUpdateMapper (STJ wire DTO -> OperationUpdateInput) and route DurableExecutionStore/DurableExecutionDriver through the kernel's processor, store, exec-0 seeding, and resume-delay helper. - Switch the durable SDK reference from a preview PackageReference to an in-repo source ProjectReference (matching how RuntimeSupport is referenced) so there is a single Amazon.Lambda.DurableExecution assembly identity across the SDK and the kernel. Stacked on the LocalEmulation kernel PR (and PR #2492); builds once both are on the target branch. No user-facing behavior change.
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.
Symptom
The AWS Lambda Test Tool v2 Blazor web UI had two static-asset serving bugs that broke interactivity, each specific to a target framework:
(A) Non-interactive on .NET 10 (any .NET 9+). Buttons don't respond,
@onclick/@bindnever fire;window.Blazorisundefined. The tell is subtle — the framework script returns HTTP 200 with a 0-byte body, so status-code checks alone look green while the browser downloads nothing:(B) Code editor dead on .NET 8 (
dotnet run). The Razor class library assets for the Monaco code editor (_content/BlazorMonaco/**) return 404, so the request/response editor never initializes — e.g. selecting an example request does not populate the input, and typing/formatting in the editor doesn't work:Root cause
Static-asset serving changed in .NET 9: framework assets (
_framework/*) and scoped CSS are served by the endpoint-routingapp.MapStaticAssets()pipeline, which reads bytes fromIWebHostEnvironment.WebRootFileProvider. Underdotnet run, neither the framework files nor RCL_content/**assets physically live inwwwroot— they live in the NuGet cache and are surfaced through the*.staticwebassets.runtime.jsonmanifest. Two things kept that manifest from being reachable:Manifest not composed outside Development. ASP.NET Core only composes the static-web-assets manifest into
WebRootFileProviderautomatically when the environment is Development (WebHost.ConfigureWebDefaultscallsStaticWebAssetsLoader.UseStaticWebAssetsonly underIsDevelopment()). This tool runs as Production by default, so the web root was a barewwwrootprovider.MapStaticAssetsserved empty (0-byte) 200s for_framework/*→ symptom (A).MapStaticAssets), the manifest was likewise never composed, and — see below — nothing read it anyway → symptom (B).Content root followed the current working directory. As an installed global tool the process launches from an arbitrary cwd;
WebRootFileProviderdefaulted tocwd/wwwroot, a nonexistent path, so every asset returned empty 200s.The classic
UseStaticFilesused an explicit bare-wwwroot provider. It was pinned to aPhysicalFileProvider(wwwroot)and never read the manifest-composedWebRootFileProvider. On net9+ this was masked becauseMapStaticAssetsreadsWebRootFileProvider; on net8 there is no such reader, so manifest-mapped_content/**assets were unreachable → symptom (B).Fix
All in
Tools/LambdaTestTool-v2/src/Amazon.Lambda.TestTool/Processes/TestToolProcess.cs:WebRootFileProviderresolves regardless of launching cwd:_framework/*+ scoped CSS via the endpoints manifest on net9+:UseStaticFilesoverWebRootFileProviderso manifest-mapped RCL_content/**assets (BlazorMonaco) resolve. There is noMapStaticAssetson net8, and the explicit wwwroot provider can't see the composed manifest:The existing wwwroot
UseStaticFilesprovider is preserved (authoritative for the installed tool, where all assets are published directly intowwwroot). For an installed tool the second net8 lookup resolves to the samewwwroot, so it is a harmless second pass.Verification — full 8-case matrix
Probed the three assets whose absence breaks the UI —
_framework/blazor.web.js(interactive circuit),_content/BlazorMonaco/.../loader.js(Monaco editor → example-request fill), andapp.css— asserting HTTP 200 with non-zero bytes across every combination of {.NET 8, .NET 10} × {Production, Development} × {dotnet run, installed tool}:(Before this change:
run/net8.0/*hadmonaco loader.js -> 404andrun/net10.0/*hadblazor.web.js -> 200, 0 bytes.) Real-browser confirmation via headless Chromium:window.Blazor=trueand no console errors on/,/documentation, and/durable-execution. Both TFMs build with 0 warnings / 0 errors; the Test Tool unit tests (which invokeStartupdirectly) pass on net8.