Skip to content

[Blazor] Replace DevServer with BlazorGateway for standalone WASM apps#65982

Open
javiercn wants to merge 5 commits intomainfrom
javiercn/blazor-gateway
Open

[Blazor] Replace DevServer with BlazorGateway for standalone WASM apps#65982
javiercn wants to merge 5 commits intomainfrom
javiercn/blazor-gateway

Conversation

@javiercn
Copy link
Copy Markdown
Member

@javiercn javiercn commented Mar 25, 2026

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 — Static BuildWebHost(string[] args) method configurable in two modes:
    • Standalone mode: Derives static web asset manifest paths from --applicationpath CLI arg (used by dotnet run and E2E tests)
    • Aspire mode: Reads ClientApps config section for multiple client apps, YARP reverse proxy, config endpoints
  • Program.cs — Entry point that calls BlazorGateway.BuildWebHost(args).Run()
  • MSBuild targets (build/Microsoft.AspNetCore.Components.Gateway.targets) — Imported by WASM projects to override dotnet run behavior: sets _WebAssemblyUserRunParameters=true, resolves manifest paths via ComputeRunArguments
  • SpaFallback.targets — Temporary target that adds {**path:nonfile} catch-all endpoint to the static web assets endpoints manifest (clones identity index.html endpoint)

Updated: E2E test infrastructure

  • BlazorWasmTestAppFixture now calls BlazorGateway.BuildWebHost() instead of DevServer
  • Components.TestServer includes BlazorGateway.cs as shared source and uses it for the "Dev server client-side blazor" scenario
  • YARP packages added via the repo's <Reference> pattern (eng/Versions.props + eng/Dependencies.props)
  • SpaFallback.targets imported into BasicTestApp, ThreadingApp, and Wasm.Performance.TestApp

Key design decisions

  • YARP baked in — No conditional compilation; the Gateway always supports reverse proxy for future Aspire integration
  • Shared source via <Compile Include>BlazorGateway.cs is included in test projects as source rather than referenced as a project, avoiding assembly conflicts with the test host's Program class
  • _RemoveTransitiveAspNetCoreFrameworkReference target — In TestServer, removes YARP's transitive FrameworkReference to Microsoft.AspNetCore.App after AddTransitiveFrameworkReferences but before ResolveTargetingPackAssets

Testing

E2E test validation in progress across 5 waves:

  • Wave 1 (smoke): StandaloneAppTest.HasTitle, HasHeading, BasicTestAppCanBeServed
  • Wave 2 (BlazorWasmTestAppFixture): All 20 tests ✅
  • Wave 3-5: Core rendering, events, forms, remaining — in progress

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is temporary until an SDK with the functionality flows here

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Temporary until the SDK update flows to asp.net core

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 a BlazorGateway.BuildWebHost(args) entrypoint and dotnet run integration 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.targets imported 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.

- 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
@javiercn javiercn force-pushed the javiercn/blazor-gateway branch from 11863e3 to faab532 Compare March 29, 2026 13:06
Comment on lines +59 to +62
// 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");
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is until we get fallbacks on the SDK

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-blazor Includes: Blazor, Razor Components

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants