.NET 8 Blazor两种场景下导航与HttpContext异常问题求助
原因
Blazor静态SSR模式下,表单提交为服务器端回发处理,NavigationManager.NavigateTo是客户端导航API,在服务器端执行时无客户端上下文,导致报错;同时同步的SaveChanges不符合异步编程规范,易造成线程阻塞。
解决方案
改用服务器端重定向方式,让表单提交方法返回IActionResult,通过RedirectToPage实现重定向,同时使用异步版本的数据库保存方法。
修改后的代码
@page "/UpsertGame" @using BlazorAppAuth.Models; @using BlazorAppAuth.Data; @inject DataContext _dataContext; @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers <h3>AddNewGames</h3> <EditForm Model="videoGame" OnSubmit="Submit" FormName="Game"> <div class="row"> <div class="col-md-3"> <label>Title</label> <InputText @bind-Value="videoGame.Title" class="form-control form-control-sm"></InputText> </div> <div class="col-md-3"> <label>Publisher</label> <InputText @bind-Value="videoGame.Publisher" class="form-control form-control-sm"></InputText> </div> <div class="col-md-3"> <label>Released Year</label> <InputNumber @bind-Value="videoGame.ReleasedYear" class="form-control form-control-sm"></InputNumber> </div> <div class="col-md-3"> <input type="submit" class="btn btn-sm btn-dark" name="Submit" /> </div> </div> </EditForm> @code { [SupplyParameterFromForm] private VideoGame videoGame { get; set; } = new(); public async Task<IActionResult> Submit() { try { _dataContext.VideoGame.Add(videoGame); var result = await _dataContext.SaveChangesAsync(); if (result == 1) return RedirectToPage("/UpsertGame"); // 保存失败返回当前页,可添加错误提示 return Page(); } catch (Exception ex) { // 处理异常,比如记录日志或添加ModelState错误 ModelState.AddModelError(string.Empty, "保存失败,请重试"); return Page(); } } }
原因
- InteractiveServer模式下HttpContext为null:该模式下组件后续交互通过SignalR连接执行,仅初始渲染阶段有HttpContext,后续操作无法访问。
- 静态SSR模式下Headers只读错误:组件渲染过程中响应已开始输出,此时调用
SignInAsync需要修改响应头设置Cookie,导致冲突。
解决方案
将登录逻辑移至服务器端的Razor Page或API控制器,避免在Blazor组件中直接操作HttpContext或修改响应头。
步骤1:创建登录处理的Razor Page
Login.cshtml.cs
using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.RazorPages; using System.Security.Claims; namespace BlazorAppAuth.Pages; [AllowAnonymous] public class LoginModel : PageModel { [BindProperty] public UserCredentials UserCredentials { get; set; } = new(); public async Task<IActionResult> OnPostAsync() { if (!ModelState.IsValid) return Page(); if (UserCredentials.Username == "Ankesh" && UserCredentials.Password == "ank") { var claims = new List<Claim> { new Claim(ClaimTypes.Name, UserCredentials.Username) }; var identity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme); var principal = new ClaimsPrincipal(identity); await HttpContext.SignInAsync(principal); return RedirectToPage("/"); } ModelState.AddModelError(string.Empty, "用户名或密码错误"); return Page(); } public class UserCredentials { public string Username { get; set; } = string.Empty; public string Password { get; set; } = string.Empty; } }
Login.cshtml
@page "/login" @model BlazorAppAuth.Pages.LoginModel <h3>登录</h3> <div class="row"> <div class="col-md-4"> <form method="post"> <div asp-validation-summary="All" class="text-danger"></div> <div class="mb-3"> <label asp-for="UserCredentials.Username" class="form-label"></label> <input asp-for="UserCredentials.Username" class="form-control" /> <span asp-validation-for="UserCredentials.Username" class="text-danger"></span> </div> <div class="mb-3"> <label asp-for="UserCredentials.Password" class="form-label"></label> <input asp-for="UserCredentials.Password" type="password" class="form-control" /> <span asp-validation-for="UserCredentials.Password" class="text-danger"></span> </div> <button type="submit" class="btn btn-dark">登录</button> </form> </div> </div>
步骤2:Blazor组件中跳转至登录页(可选)
如果需要在Blazor组件中触发登录跳转,直接使用NavigationManager即可(静态SSR或InteractiveServer模式下均有效):
@inject NavigationManager NavigationManager <button class="btn btn-link" @onclick="() => NavigationManager.NavigateTo("/login")"> 登录 </button>
内容的提问来源于stack exchange,提问作者Ankesh kumar
相关产品推荐
相关产品推荐

