.NET 8中如何实现Blazor Server与Blazor WebAssembly共存运行?
.NET 8中Blazor WebAssembly与服务器端渲染共存的解决方案
针对你遇到的WASM入口无法初始化、客户端专属服务报错的问题,下面是几种可行的实现方案:
方案1:按路由拆分渲染逻辑
在Server项目的App.razor里,根据访问路径判断是用SSR还是WASM模式,分别加载对应程序集的路由:
@using Client @using Server @inject NavigationManager NavigationManager @{ var currentPath = NavigationManager.Uri; // 定义需要SSR的路径,比如登录、重定向页 var useServerRender = currentPath.Contains("/login") || currentPath.Contains("/redirect"); } @if (useServerRender) { <Router AppAssembly="@typeof(Server.Program).Assembly"> <Found Context="routeData"> <RouteView RouteData="@routeData" DefaultLayout="@typeof(Server.Shared.MainLayout)" /> </Found> <NotFound> <LayoutView Layout="@typeof(Server.Shared.MainLayout)"> <p>服务器端页面未找到</p> </LayoutView> </NotFound> </Router> } else { <Router AppAssembly="@typeof(Client.Program).Assembly"> <Found Context="routeData"> <RouteView RouteData="@routeData" DefaultLayout="@typeof(Client.Shared.MainLayout)" @rendermode="new InteractiveWebAssemblyRenderMode(prerender: false)" /> </Found> <NotFound> <LayoutView Layout="@typeof(Client.Shared.MainLayout)"> <p>客户端页面未找到</p> </LayoutView> </NotFound> </Router> }
注意:Server项目必须引用Client项目,才能访问客户端的布局和组件。
方案2:通过端点配置区分渲染模式
在Server项目的Program.cs中,针对不同路径配置不同的根组件和渲染模式:
builder.Services.AddRazorComponents() .AddInteractiveServerComponents() .AddInteractiveWebAssemblyComponents(); var app = builder.Build(); // 配置SSR专属路径(登录、重定向) app.MapWhen(ctx => ctx.Request.Path.StartsWithSegments("/login") || ctx.Request.Path.StartsWithSegments("/redirect"), subApp => { subApp.MapRazorComponents<Server.App>() .AddInteractiveServerRenderMode() .AddAdditionalAssemblies(typeof(Server.Program).Assembly); }); // 配置WASM应用的默认路径 app.MapRazorComponents<Client.App>() .AddInteractiveWebAssemblyRenderMode(prerender: false) .AddAdditionalAssemblies(typeof(Client.Program).Assembly);
这种方式需要给Server和Client分别创建独立的App.razor,各自管理对应模式下的路由规则。
方案3:组件级指定渲染模式(混合页面场景)
如果只是部分页面需要SSR,其余保持WASM,可以在统一使用Client路由的基础上,给特定页面标记SSR模式:
- 保持Server项目
App.razor指向Client程序集:
<Router AppAssembly="@typeof(Client.Program).Assembly"> <Found Context="routeData"> <RouteView RouteData="@routeData" DefaultLayout="@typeof(Client.Shared.MainLayout)" /> </Found> <NotFound> <LayoutView Layout="@typeof(Client.Shared.MainLayout)"> <p>页面未找到</p> </LayoutView> </NotFound> </Router>
- 在需要SSR的页面(比如
Login.razor)顶部添加渲染模式标记:
@page "/login" @rendermode InteractiveServerRenderMode <h1>登录页(SSR)</h1> <!-- 登录表单内容 -->
- 在Server项目
Program.cs中同时注册两种渲染模式:
builder.Services.AddRazorComponents() .AddInteractiveServerComponents() .AddInteractiveWebAssemblyComponents(); app.MapRazorComponents<Client.App>() .AddInteractiveWebAssemblyRenderMode(prerender: false) .AddInteractiveServerRenderMode() .AddAdditionalAssemblies(typeof(Server.Program).Assembly);
这种方案下,WASM的Program.cs会正常初始化,只有标记了SSR的页面会在服务器端渲染,避免客户端专属服务在服务器端执行报错。
核心注意事项
- 客户端专属操作(比如
localStorage、IJSRuntime调用)必须放到OnAfterRenderAsync生命周期里,或者用OperatingSystem.IsBrowser()判断环境后再执行,防止服务器端渲染时触发错误:
protected override async Task OnAfterRenderAsync(bool firstRender) { if (firstRender && OperatingSystem.IsBrowser()) { // 仅在浏览器环境执行客户端逻辑 var storedValue = await localStorage.GetItemAsync<string>("user_token"); } }
- 确保Server项目正确引用Client项目,共享组件和服务要保证两端都能访问。
- SSR页面里不要引用仅客户端可用的组件或服务,避免服务器端实例化失败。
内容的提问来源于stack exchange,提问作者dunxz
相关产品推荐
相关产品推荐

