0

0

c# 在 Blazor Server 中处理并发事件和状态更新

畫卷琴夢

畫卷琴夢

发布时间:2026-01-12 08:28:03

|

349人浏览过

|

来源于php中文网

原创

Blazor Server事件处理默认非线程安全,需用InvokeAsync确保UI更新线程安全,并配合CancellationToken及时取消异步操作以防ObjectDisposedException。

c# 在 blazor server 中处理并发事件和状态更新

Blazor Server 的事件处理默认不是线程安全的

Blazor Server 使用 SignalR 长连接通信,所有 UI 事件(如 @onclick)都在同一个逻辑“请求上下文”中同步执行,但不等于线程安全。多个用户操作或快速连续点击可能触发并发调用,而组件实例是按用户会话单例复用的,StateHasChanged() 和字段更新若未加防护,会导致状态错乱或 ObjectDisposedException

  • 常见错误现象:System.ObjectDisposedException: Cannot access a disposed object,尤其在异步操作完成前组件已卸载
  • 典型场景:按钮连续点击触发同一 async Task 方法;后台任务(如 Timer)更新组件字段后调用 StateHasChanged()
  • 关键限制:Blazor Server 不允许从非渲染线程直接调用 StateHasChanged() —— 必须通过 InvokeAsync()

InvokeAsync() 包裹所有跨上下文的状态更新

即使你在 async 方法中 await 了外部服务,回调一旦脱离原始渲染上下文(例如从 Task.RunTimer 或第三方库回调中返回),就必须显式切回组件上下文才能安全更新状态或触发重绘

private async Task HandleClick()
{
    // ❌ 危险:若 DoWorkAsync 内部用了 Task.Run 或延迟回调,后续更新可能并发
    var result = await DoWorkAsync();
    currentData = result;
    StateHasChanged(); // 可能抛 ObjectDisposedException

    // ✅ 正确:确保所有 UI 更新都经 InvokeAsync 调度
    await InvokeAsync(() =>
    {
        currentData = result;
        StateHasChanged();
    });
}
  • InvokeAsync(Action) 是线程安全的入口,Blazor 会排队执行并自动忽略已销毁组件的调用
  • 不要对每个字段赋值都单独调用 InvokeAsync;合并到一个委托里减少调度开销
  • 如果方法本身被多次快速调用,仅靠 InvokeAsync 不足以防重复提交 —— 还需业务层节流或禁用按钮

避免在事件处理中裸写 Task.Run 或长时间运行同步代码

Blazor Server 渲染线程(即 SynchronizationContext)是单线程的。在事件处理器里直接调用阻塞式 IO 或 CPU 密集型代码(如 Thread.Sleep、大数组排序、XML 解析),会卡住整个用户的会话通道,影响响应甚至引发超时断连。

OmniAudio
OmniAudio

OmniAudio 是一款通过 AI 支持将网页、Word 文档、Gmail 内容、文本片段、视频音频文件都转换为音频播客,并生成可在常见 Podcast ap

下载
  • 错误示例:Task.Run(() => { Thread.Sleep(2000); return GetData(); }) —— 没解决根本问题,反而增加线程调度负担
  • 正确做法:将真正耗时操作移至后台服务(如 IHostedService),用 ChannelEventCallback 通知组件;或使用真正异步 API(HttpClient.GetAsyncStream.ReadAsync
  • 若必须同步计算,至少加取消检查:if (CancellationToken.IsCancellationRequested) return;,并在组件 Dispose 时传递取消令牌

CancellationToken 主动取消挂起的异步操作

用户导航离开页面、组件被销毁后,未完成的 await 任务仍可能继续执行,并在完成后尝试调用 InvokeAsync —— 此时组件已释放,InvokeAsync 会静默丢弃该调用,但后台任务仍在浪费资源。

private CancellationTokenSource? _cts;

protected override void OnInitialized()
{
    _cts = new();
}

private async Task LoadData()
{
    try
    {
        var data = await _api.GetDataAsync(_cts.Token); // 传入 token
        await InvokeAsync(() =>
        {
            items = data;
            StateHasChanged();
        });
    }
    catch (OperationCanceledException)
    {
        // 被主动取消,无需处理
    }
}

public void Dispose()
{
    _cts?.Cancel();
    _cts?.Dispose();
}
  • 每次启动新异步操作前应取消旧的 CancellationTokenSource,防止竞态残留
  • 不要依赖 IsDisposed 判断组件状态 —— InvokeAsync 已内置防护,重点是及时取消上游 I/O
  • 第三方库若不支持 CancellationToken,考虑用 Task.WaitAsync(TimeSpan, CancellationToken) 包装超时
Blazor Server 的并发风险不在“多线程争抢”,而在“生命周期与异步生命周期错位”。最易被忽略的是:**你以为的“顺序执行”其实依赖于 SignalR 消息到达顺序和服务器端队列调度,而非代码书写顺序**。任何绕过 InvokeAsync 的 UI 更新、任何未绑定取消令牌的 await、任何未清理的后台计时器,都会在高交互场景下暴露问题。

相关专题

更多
if什么意思
if什么意思

if的意思是“如果”的条件。它是一个用于引导条件语句的关键词,用于根据特定条件的真假情况来执行不同的代码块。本专题提供if什么意思的相关文章,供大家免费阅读。

731

2023.08.22

pdf怎么转换成xml格式
pdf怎么转换成xml格式

将 pdf 转换为 xml 的方法:1. 使用在线转换器;2. 使用桌面软件(如 adobe acrobat、itext);3. 使用命令行工具(如 pdftoxml)。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

1871

2024.04.01

xml怎么变成word
xml怎么变成word

步骤:1. 导入 xml 文件;2. 选择 xml 结构;3. 映射 xml 元素到 word 元素;4. 生成 word 文档。提示:确保 xml 文件结构良好,并预览 word 文档以验证转换是否成功。想了解更多xml的相关内容,可以阅读本专题下面的文章。

2085

2024.08.01

xml是什么格式的文件
xml是什么格式的文件

xml是一种纯文本格式的文件。xml指的是可扩展标记语言,标准通用标记语言的子集,是一种用于标记电子文件使其具有结构性的标记语言。想了解更多相关的内容,可阅读本专题下面的相关文章。

974

2024.11.28

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

479

2023.08.10

Python 多线程与异步编程实战
Python 多线程与异步编程实战

本专题系统讲解 Python 多线程与异步编程的核心概念与实战技巧,包括 threading 模块基础、线程同步机制、GIL 原理、asyncio 异步任务管理、协程与事件循环、任务调度与异常处理。通过实战示例,帮助学习者掌握 如何构建高性能、多任务并发的 Python 应用。

143

2025.12.24

Java 并发编程高级实践
Java 并发编程高级实践

本专题深入讲解 Java 在高并发开发中的核心技术,涵盖线程模型、Thread 与 Runnable、Lock 与 synchronized、原子类、并发容器、线程池(Executor 框架)、阻塞队列、并发工具类(CountDownLatch、Semaphore)、以及高并发系统设计中的关键策略。通过实战案例帮助学习者全面掌握构建高性能并发应用的工程能力。

60

2025.12.01

Golang channel原理
Golang channel原理

本专题整合了Golang channel通信相关介绍,阅读专题下面的文章了解更多详细内容。

244

2025.11.14

c++主流开发框架汇总
c++主流开发框架汇总

本专题整合了c++开发框架推荐,阅读专题下面的文章了解更多详细内容。

80

2026.01.09

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Django 教程
Django 教程

共28课时 | 3万人学习

SciPy 教程
SciPy 教程

共10课时 | 1.1万人学习

Sass 教程
Sass 教程

共14课时 | 0.8万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号