[Blazor] Replace DevServer with BlazorGateway for standalone WASM apps#65982
Conversation
There was a problem hiding this comment.
This is temporary until an SDK with the functionality flows here
There was a problem hiding this comment.
Temporary until the SDK update flows to asp.net core
There was a problem hiding this comment.
Pull request overview
This PR replaces the Blazor WebAssembly DevServer with a new Microsoft.AspNetCore.Components.Gateway host for serving standalone WASM apps in development/testing, and updates test/benchmark assets to use the new Gateway (including SPA fallback routing via static web assets endpoints).
Changes:
- Adds a new Gateway project (
Microsoft.AspNetCore.Components.Gateway) with aBlazorGateway.BuildWebHost(args)entrypoint anddotnet runintegration via MSBuild targets. - Updates Components test infrastructure (E2E + Components.TestServer) to start the Gateway instead of DevServer and passes static web assets manifests explicitly.
- Introduces a temporary
SpaFallback.targetsimported by multiple WASM test apps to add a{**path:nonfile}SPA fallback endpoint.
Reviewed changes
Copilot reviewed 19 out of 19 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| src/WebAssembly/testassets/SpaFallback.targets | New MSBuild targets to inject SPA fallback static web asset endpoint. |
| src/Components/test/testassets/GlobalizationWasmApp/GlobalizationWasmApp.csproj | Imports SPA fallback targets for this test asset. |
| src/Components/test/testassets/Components.TestServer/Program.cs | Switches dev-host scenario to use BlazorGateway and passes manifests via args. |
| src/Components/test/testassets/Components.TestServer/Components.TestServer.csproj | Uses shared-source BlazorGateway.cs, adds YARP refs, and removes transitive framework ref. |
| src/Components/test/testassets/BasicTestApp/BasicTestApp.csproj | Imports SPA fallback targets. |
| src/Components/test/E2ETest/Microsoft.AspNetCore.Components.E2ETests.csproj | Normalizes project file header/encoding. |
| src/Components/test/E2ETest/Infrastructure/ServerFixtures/BlazorWasmTestAppFixture.cs | Uses BlazorGateway and passes static web assets manifests to host. |
| src/Components/benchmarkapps/Wasm.Performance/TestApp/Wasm.Performance.TestApp.csproj | Imports SPA fallback targets for benchmark app. |
| src/Components/WebAssembly/testassets/ThreadingApp/ThreadingApp.csproj | Imports SPA fallback targets. |
| src/Components/WebAssembly/testassets/StandaloneApp/StandaloneApp.csproj | Imports Gateway run targets and SPA fallback; sets Gateway DLL location override. |
| src/Components/WebAssembly/testassets/SpaFallback.targets | New MSBuild targets to inject SPA fallback static web asset endpoint (Components copy). |
| src/Components/Gateway/src/build/Microsoft.AspNetCore.Components.Gateway.targets | Overrides dotnet run args for WASM projects to launch Gateway with manifest paths. |
| src/Components/Gateway/src/blazor-gateway.runtimeconfig.json.in | Adds runtimeconfig template for the packaged Gateway tool. |
| src/Components/Gateway/src/Program.cs | Gateway entrypoint calling BlazorGateway.BuildWebHost(args).Run(). |
| src/Components/Gateway/src/Microsoft.AspNetCore.Components.Gateway.nuspec | Packages Gateway tool + build targets into the shipping NuGet package. |
| src/Components/Gateway/src/Microsoft.AspNetCore.Components.Gateway.csproj | New shipping project (Web SDK) with YARP/service-discovery references and pack settings. |
| src/Components/Gateway/src/BlazorGateway.cs | Implements Gateway host setup: static web assets, optional YARP proxy, app config endpoints, and static assets mapping per client app. |
| eng/Versions.props | Adds version properties for YARP + service discovery packages. |
| eng/Dependencies.props | Adds YARP + service discovery packages to dependency tracking. |
3576550 to
11863e3
Compare
11863e3 to
faab532
Compare
| // SPA fallback: serve index.html for any non-file URL path, similar to | ||
| // the old DevServer's MapFallbackToFile("index.html"). This is registered | ||
| // after MapStaticAssets so that specific static file routes take precedence. | ||
| app.MapFallbackToFile("index.html"); |
There was a problem hiding this comment.
This is until we get fallbacks on the SDK
|
|
4fe2b05 to
b9e014d
Compare
ilonatommy
left a comment
There was a problem hiding this comment.
Ready for shipping after merge conflicts resolving and one more nit.
- Single Program.cs with top-level statements, pure config-driven
- Supports standalone (MSBuild targets) and Aspire (env vars/YARP)
- Gateway targets: _WebAssemblyUserRunParameters to skip WasmAppHost,
AfterTargets ComputeRunArguments with ResolveStaticWebAssetsConfiguration
to resolve manifest paths via Path.Combine(MSBuildProjectDirectory)
- Temporary SpaFallback.targets in testassets: pure MSBuild target that
clones identity index.html endpoint as {**path:nonfile} catch-all
(replaces inline C# task, will be removed when SDK ships
StaticWebAssetSpaFallbackEnabled)
- Update StandaloneApp.csproj to import Gateway + SpaFallback targets
- Extract BlazorGateway.BuildWebHost() into BlazorGateway.cs (shared source) - Update Components.TestServer and BlazorWasmTestAppFixture to use BlazorGateway - Add YARP packages (Yarp.ReverseProxy, ServiceDiscovery) via repo's <Reference> pattern - Add SpaFallback.targets to BasicTestApp, ThreadingApp, and Wasm.Performance.TestApp - Remove Program.BuildWebHost.cs Compile Include from E2ETests (gets it via TestServer ref)
Pass explicit --staticWebAssets, --ClientApps:app:EndpointsManifest, and --ClientApps:app:PathPrefix arguments from call sites instead of deriving manifest paths inside BlazorGateway. Add SpaFallback.targets to GlobalizationWasmApp.
SpaFallback.targets added a {**path:nonfile} catch-all to BasicTestApp's endpoint manifest, which propagated to Components.TestServer. MapStaticAssets hardcodes Order=-100 on all endpoints, giving the catch-all higher priority than Razor component routes (Order=0), causing all non-file URLs to serve index.html instead of server-rendered pages.
- Remove SpaFallback.targets import from BasicTestApp.csproj
- Replace the .Add() Order-override in BlazorGateway with MapFallbackToFile, matching the old DevServer approach
- Add Microsoft.Extensions.ServiceDiscovery and Microsoft.Extensions.ServiceDiscovery.Yarp to Version.Details.xml so Maestro auto-updates them from dotnet/extensions. - Add version property mappings in Version.Details.props. - Remove duplicate manual version entries from Versions.props. - Update ServiceDiscovery packages from 9.2.0 to 10.4.1. - Yarp.ReverseProxy remains as a manual external dependency. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ails.props The Maestro-managed PackageVersion definitions were missing from the auto-generated section, causing NU1015 (no version specified) errors. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…gets comment - Fix tfm in blazor-gateway.runtimeconfig.json.in from net10.0 to net11.0 - Add _CreateRuntimeConfig target to Gateway csproj (port from DevServer) so the .in template is processed via GenerateFileFromTemplate - Add GenerateRuntimeConfigurationFiles=false to use our custom template - Add XML comment explaining _WebAssemblyUserRunParameters in Gateway.targets Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
a3c3df4 to
b4aad61
Compare
…view Demonstrates hosting a standalone Blazor WASM app behind the new Blazor Gateway (PR dotnet/aspnetcore#65982) instead of the legacy Blazor Dev Server: - ClientApps:app:EndpointsManifest serves WASM static assets - ReverseProxy section uses YARP to proxy /api/* to the Backend project - ClientApps:app:ConfigEndpointPath returns inline JSON config to the client - Service discovery via AddServiceDiscovery + AddServiceDiscoveryDestinationResolver The local Gateway project mirrors the upstream BlazorGateway.BuildWebHost. When Microsoft.AspNetCore.Components.Gateway ships, replace it with a single PackageReference in Client.csproj (in place of the DevServer reference). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Documents how to opt in to the new Blazor Gateway (PR dotnet/aspnetcore#65982) in a standalone Blazor WebAssembly app: swapping the DevServer reference for Microsoft.AspNetCore.Components.Gateway, configuring YARP proxying to backend APIs, and exposing a runtime config endpoint to the client. Links to the GatewayDemo sample in danroth27/AspNetCore11Samples for an end-to-end setup. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Drop Microsoft.AspNetCore.Components.WebAssembly.DevServer reference. - Add a top-level Gateway/ project (local stand-in for the upcoming Microsoft.AspNetCore.Components.Gateway package, dotnet/aspnetcore#65982). - Add a top-level BackendApi/ project (minimal /weather endpoint) so the Blazor app can demonstrate the Gateway's YARP proxying support. - Wire up Weather.razor to call /api/weather (proxied through the Gateway to BackendApi) instead of the static sample-data/weather.json. - Add Pages/AppConfig.razor demonstrating the Gateway's config endpoint: the Gateway returns inline JSON from /_app/config (banner text + feature flags + environment) and the page renders it. - Drop the GatewayDemo/ subdirectory it replaces. - Drop AddServiceDiscovery / AddServiceDiscoveryDestinationResolver from the Gateway: these are an Aspire-style integration and aren't needed when YARP destinations use plain absolute URLs. - Replace MapFallbackToFile (requires WebRoot, which the Gateway has none of) with a MapFallback that resolves /index.html from the static-asset endpoint manifest, so SPA routes return 200. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Summary
Introduces
Microsoft.AspNetCore.Components.Gateway— a lightweight ASP.NET Core host that replaces the DevServer for serving standalone Blazor WebAssembly applications during development and production.Changes
New: Gateway project (
src/Components/Gateway/src/)BlazorGateway.cs— StaticBuildWebHost(string[] args)method configurable in two modes:--applicationpathCLI arg (used bydotnet runand E2E tests)ClientAppsconfig section for multiple client apps, YARP reverse proxy, config endpointsProgram.cs— Entry point that callsBlazorGateway.BuildWebHost(args).Run()build/Microsoft.AspNetCore.Components.Gateway.targets) — Imported by WASM projects to overridedotnet runbehavior: sets_WebAssemblyUserRunParameters=true, resolves manifest paths viaComputeRunArguments{**path:nonfile}catch-all endpoint to the static web assets endpoints manifest (clones identityindex.htmlendpoint)Updated: E2E test infrastructure
BlazorWasmTestAppFixturenow callsBlazorGateway.BuildWebHost()instead of DevServerComponents.TestServerincludesBlazorGateway.csas shared source and uses it for the "Dev server client-side blazor" scenario<Reference>pattern (eng/Versions.props+eng/Dependencies.props)SpaFallback.targetsimported into BasicTestApp, ThreadingApp, and Wasm.Performance.TestAppKey design decisions
<Compile Include>—BlazorGateway.csis included in test projects as source rather than referenced as a project, avoiding assembly conflicts with the test host'sProgramclass_RemoveTransitiveAspNetCoreFrameworkReferencetarget — In TestServer, removes YARP's transitiveFrameworkReferencetoMicrosoft.AspNetCore.AppafterAddTransitiveFrameworkReferencesbut beforeResolveTargetingPackAssetsTesting
E2E test validation in progress across 5 waves:
StandaloneAppTest.HasTitle,HasHeading,BasicTestAppCanBeServed✅