Blazor Server调用REST后ProtectedSessionStorage.SetAsync抛任务取消异常
问题分析与解决方案
核心问题点
async void导致的上下文丢失
Blazor Server中,事件处理方法使用async void会破坏组件的同步上下文,后续调用ProtectedSessionStorage.SetAsync(依赖JS互操作)时,可能因为上下文已失效导致任务被取消。类型不匹配错误
你的LoginSync方法返回AuthenticatedUserResponse?,但Login方法中用TokenContainer类型接收,这会导致编译错误或运行时类型转换异常,间接引发后续操作失败。异常被静默吞掉
LoginSync中捕获所有异常并返回null,无法排查登录请求过程中是否出现网络错误、序列化失败等问题,掩盖了真实故障原因。组件状态检查缺失
如果登录请求耗时较长,组件可能已被销毁,此时调用ProtectedSessionStorage会触发JS互操作超时,抛出任务取消异常。
修复步骤
1. 将async void改为async Task
Blazor事件处理必须使用async Task来维持上下文:
private async Task Login() { var authResponse = await LoginService.LoginSync(VM.Username, VM.Password); if (authResponse != null && !IsDisposed) { await ProtectedSessionStorage.SetAsync("access", authResponse.AccessToken); // 登录成功后的逻辑,比如跳转至主页 } else { // 处理登录失败场景,比如提示用户 } }
2. 统一类型匹配
确保LoginSync返回的类型与接收端一致,删除冗余的TokenContainer类,直接使用AuthenticatedUserResponse:
// 删除不必要的TokenContainer类,确保AuthenticatedUserResponse包含AccessToken和RefreshToken public class AuthenticatedUserResponse { public string AccessToken { get; set; } = string.Empty; public string RefreshToken { get; set; } = string.Empty; }
3. 修复异常处理逻辑
不要静默吞掉所有异常,改为针对性捕获并抛出/记录,便于排查问题:
internal async Task<AuthenticatedUserResponse?> LoginSync(string username, string password) { try { var request = new LoginRequest() { Password = password, Username = username }; var stringContent = GetContentFromContainer(request); var response = await this.Client.PostAsync($"{BASE_ROUTE}/{LOGIN_ACTION}", stringContent); // 主动抛出HTTP错误,避免返回null掩盖问题 response.EnsureSuccessStatusCode(); var content = await response.Content.ReadAsStringAsync(); return JsonSerializer.Deserialize<AuthenticatedUserResponse>(content, JsonOptions); } catch (HttpRequestException ex) { // 记录日志(如注入ILogger),或返回null并提示用户 // _logger.LogError(ex, "登录请求失败,状态码:{StatusCode}", ex.StatusCode); return null; } catch (JsonException ex) { // 处理序列化失败 // _logger.LogError(ex, "登录响应序列化失败"); return null; } }
4. 检查组件活跃状态
调用ProtectedSessionStorage前,通过IsDisposed属性确认组件未被销毁,避免JS互操作超时:
if (authResponse != null && !IsDisposed) { await ProtectedSessionStorage.SetAsync("access", authResponse.AccessToken); }
5. 确认依赖注入正确性
确保ProtectedSessionStorage和LoginService已正确注入组件:
[Inject] protected ProtectedSessionStorage ProtectedSessionStorage { get; set; } = default!; [Inject] protected LoginService LoginService { get; set; } = default!;
额外注意事项
- 如果登录接口响应耗时超过5秒(Blazor JS互操作默认超时),可以在
Program.cs中调整超时时间:builder.Services.AddServerSideBlazor() .AddHubOptions(options => { options.ClientTimeoutInterval = TimeSpan.FromSeconds(10); options.HandshakeTimeout = TimeSpan.FromSeconds(10); }); - 确保
ProtectedSessionStorage的调用在组件的生命周期内(如OnInitializedAsync、事件处理方法),不要在后台线程中调用。
内容的提问来源于stack exchange,提问作者Esko
相关产品推荐
相关产品推荐

