.NET 6升级至.NET 8后Blazor NavigateTo跳转失效问题
我把正常运行的.NET 6纯WebAssembly项目升级到.NET 8,保留原有架构并开启首页服务器端渲染(SSR)优化体验。需求是用户点击页面元素后跳转登录页,登录后返回原页面(通过本地存储记录元素),但用NavigateTo跳转至带ReturnUrl="/"的登录页时出现「Not Found」错误,代码在OnAfterRender方法中执行,确认是浏览器端操作。
当前配置代码
Routes.Razor配置
<Router AppAssembly="typeof(Program).Assembly"> <Found Context="routeData"> <AuthorizeRouteView RouteData="routeData" DefaultLayout="typeof(Layout.MainLayout)"> <NotAuthorized> <RedirectToLogin /> </NotAuthorized> </AuthorizeRouteView> <FocusOnNavigate RouteData="routeData" Selector="h1" /> </Found> </Router>
App.razor渲染模式配置
<HeadOutlet @rendermode="RenderModeForPage" />
对应后台逻辑:
public partial class App { [CascadingParameter] private HttpContext HttpContext { get; set; } = default!; private IComponentRenderMode? RenderModeForPage => HttpContext.Request.Path.StartsWithSegments("/Account") ? null : RenderMode.InteractiveWebAssembly; }
跳转测试代码
尝试用GetUriWithQueryParameters生成链接返回null:
string reg = _navigationManager.GetUriWithQueryParameters("Account/Login", new Dictionary<string, object?> { ["ReturnUrl"] = "/" }); _navigationManager.NavigateTo(reg);
简化测试:按钮直接跳转正常,但NavigateTo触发404:
<div class="ctr"> <div class="clnk"> @* <Button Size="Size.Small" Color="Color.Primary" Type="ButtonType.Link" To="Account/Login">Login/Sign Up</Button> *@ <Button Size="Size.Small" Color="Color.Primary" Clicked="Login">Login/Sign Up</Button> </div> </div>
public void Login() { _navigationManager.NavigateTo("Account/Login"); }
登录页路由配置
@page "/Account/Login"
完整App.razor代码
<!DOCTYPE html> <html lang="en"> <head> <!-- Google tag (gtag.js) --> GOOGLE STUFF <!-- END of Google tag (gtag.js) --> <meta charset="utf-8" /> <!--Google Fonts--> GOOGLE FONTS STUFF <title>WMAP</title> <base href="/" /> <!--OTHER SCRIPTS inside of head section --> LINKS TO OTHER SCRIPTS <!-- END OF OTHER SCRIPTS head section --> LINKS TO STYLESHEETS <link rel="icon" sizes="512x512" href="icon-512.png" /> <link rel="icon" sizes="192x192" href="icon-192.png" /> <!-- Meta Pixel Code --> META (FACEBOOK/INSTA) Code <!-- End Meta Pixel Code --> <HeadOutlet @rendermode="RenderModeForPage" /> </head> <body> <Routes @rendermode="RenderModeForPage" /> <script src="_framework/blazor.web.js"></script> PAYMENT PROVIDER SCRIPTS <!-- WMAP JS--> <script src="/js/WMAP.js" asp-append-version="true"></script> <!-- /WMAP JS--> </body> </html>
public partial class App { [CascadingParameter] private HttpContext HttpContext { get; set; } = default!; private IComponentRenderMode? RenderModeForPage => HttpContext.Request.Path.StartsWithSegments("/Account") ? null : RenderMode.InteractiveWebAssembly; }
问题原因与解决方案
核心原因
你遇到的404是因为浏览器端的Blazor WASM路由器无法识别服务器端渲染(SSR)的路由。当在InteractiveWebAssembly模式下使用NavigateTo("Account/Login")时,客户端路由器会尝试在WASM组件中匹配该路由,但你的登录页是SSR模式(RenderModeForPage对Account路径返回null,使用服务器端渲染),客户端找不到对应组件,就触发404。
而<Button Type="Link">能正常跳转,是因为它生成的是标准HTML锚点链接,浏览器会直接向服务器发请求,由服务器处理SSR路由匹配,因此能正常访问。
解决办法
1. 使用绝对路径触发硬导航
在NavigateTo中给路径加上/前缀,强制浏览器向服务器发送请求,跳过客户端路由匹配:
// 基础跳转 _navigationManager.NavigateTo("/Account/Login"); // 带ReturnUrl的正确写法(编码避免特殊字符问题) var currentUrl = _navigationManager.Uri; _navigationManager.NavigateTo($"/Account/Login?ReturnUrl={Uri.EscapeDataString(currentUrl)}");
2. 修复GetUriWithQueryParameters的使用
该方法第一个参数需要绝对路径(或基于当前页面的相对路径),加上前缀即可正常生成链接:
string reg = _navigationManager.GetUriWithQueryParameters("/Account/Login", new Dictionary<string, object?> { ["ReturnUrl"] = "/" }); _navigationManager.NavigateTo(reg);
3. 可选:客户端路由 fallback 配置
如果希望客户端路由器兼容SSR路由,可在Routes.Razor中添加<NotFound>区块,当客户端找不到路由时触发硬导航:
<Router AppAssembly="typeof(Program).Assembly"> <Found Context="routeData"> <!-- 原有内容 --> </Found> <NotFound> <script>window.location.href = window.location.pathname + window.location.search;</script> </NotFound> </Router>
优先推荐第一种方法,更直观且符合SSR路由的设计逻辑。
内容的提问来源于stack exchange,提问作者Brett JB

