.NET 7 Blazor Server登录/登出时WebSocket重连异常求助
问题排查:Blazor Server登录/登出时WebSocket重连异常
原因分析
- 登录/登出操作触发
AuthenticationStateProvider的NotifyAuthenticationStateChanged方法时,若时机不当(比如WebSocket连接状态不稳定),会引发Blazor SignalR连接冲突,导致连接断开重连。 - 自定义
CustomAuthenticationStateProvider中异步操作处理不严谨,比如身份状态未完全更新就通知状态变更,造成客户端与服务端状态同步异常,触发WebSocket状态错误。 - 登录/登出逻辑使用了非Blazor原生跳转方式(如
window.location.href强制刷新),直接中断当前SignalR连接,Blazor会自动尝试重连从而出现提示。
解决方法
1. 优化CustomAuthenticationStateProvider实现
确保身份状态稳定后再触发状态变更通知,避免异步竞态问题:
public class CustomAuthenticationStateProvider : AuthenticationStateProvider { private readonly HttpClient _httpClient; private AuthenticationState _cachedState; public CustomAuthenticationStateProvider(HttpClient httpClient) { _httpClient = httpClient; _cachedState = new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity())); } public override async Task<AuthenticationState> GetAuthenticationStateAsync() { try { var response = await _httpClient.GetAsync("/api/auth/currentuser"); if (response.IsSuccessStatusCode) { var user = await response.Content.ReadFromJsonAsync<ClaimsPrincipal>(); _cachedState = new AuthenticationState(user); } else { _cachedState = new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity())); } } catch { _cachedState = new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity())); } return _cachedState; } public void UpdateAuthenticationState(ClaimsPrincipal user) { _cachedState = new AuthenticationState(user); // 确保状态更新完成后再通知客户端 NotifyAuthenticationStateChanged(Task.FromResult(_cachedState)); } }
2. 修正登录/登出的状态更新与导航逻辑
使用Blazor原生状态通知和导航方式,避免强制刷新中断连接:
@page "/login" @inject CustomAuthenticationStateProvider AuthStateProvider @inject NavigationManager NavManager @inject HttpClient Http <div> <input @bind="_username" placeholder="用户名" /> <input @bind="_password" type="password" placeholder="密码" /> <button @onclick="LoginAsync">登录</button> </div> @code { private string _username; private string _password; private async Task LoginAsync() { var loginModel = new { Username = _username, Password = _password }; var response = await Http.PostAsJsonAsync("/api/auth/login", loginModel); if (response.IsSuccessStatusCode) { var user = await response.Content.ReadFromJsonAsync<ClaimsPrincipal>(); // 更新身份状态,由AuthStateProvider同步到客户端 AuthStateProvider.UpdateAuthenticationState(user); // 使用Blazor导航,不强制刷新页面 NavManager.NavigateTo("/", forceLoad: false); } else { // 处理登录失败逻辑,比如提示错误信息 } } }
3. 登出逻辑对应调整
@inject CustomAuthenticationStateProvider AuthStateProvider @inject NavigationManager NavManager <button @onclick="LogoutAsync">登出</button> @code { private async Task LogoutAsync() { await Http.PostAsync("/api/auth/logout", null); // 更新为匿名身份 AuthStateProvider.UpdateAuthenticationState(new ClaimsPrincipal(new ClaimsIdentity())); // Blazor原生导航 NavManager.NavigateTo("/login", forceLoad: false); } }
4. 检查SignalR Hub配置
确保Program.cs中Blazor Hub的超时配置合理,避免连接提前断开:
builder.Services.AddServerSideBlazor() .AddHubOptions(options => { options.ClientTimeoutInterval = TimeSpan.FromSeconds(30); options.KeepAliveInterval = TimeSpan.FromSeconds(15); });
内容的提问来源于stack exchange,提问作者Robert
相关产品推荐
相关产品推荐

