You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Blazor组件中通过SignalR取消Hub中的长运行异步任务

如何取消SignalR Hub中的长运行异步任务

问题场景

在Blazor组件中,点击按钮时通过取消令牌调用Hub异步方法:

tokensource = new CancellationTokenSource();
token = tokensource.Token;
await _hubConnection.SendAsync("MachineOperationOnServer", MachineID, cancellationToken:token).ConfigureAwait(false);

点击取消按钮时触发取消操作:

tokensource.Cancel();

但当前Hub中的MachineOperationOnServer方法无法响应取消请求,原代码如下:

public async Task MachineOperationOnServer(int machineID)
{
    await Task.Factory.StartNew(async () =>
    {
        int progressPer = 0;

        for (int i = 1; i < 20; i++)
        {
            progressPer = Convert.ToInt32(((decimal)i / 20) * 100);
            await Clients.Client(Context.ConnectionId).SendAsync("ProgressOnClient", progressPer);
            Thread.Sleep(1000);                    
        }
    });
}

解决方案

要实现取消长运行任务,需从以下三点修改代码:

  1. 将取消令牌传入Hub方法
    SignalR支持在调用Hub方法时自动传递取消令牌,只需修改Hub方法的签名,添加CancellationToken参数:

    public async Task MachineOperationOnServer(int machineID, CancellationToken cancellationToken)
    
  2. 替换阻塞操作并检查取消令牌

    • 用await Task.Delay(1000, cancellationToken)替代Thread.Sleep(1000):Thread.Sleep是同步阻塞操作,无法响应取消信号;Task.Delay支持传入取消令牌,会在令牌触发取消时抛出OperationCanceledException。
    • 在循环的每一步主动检查取消令牌,确保任务能及时终止。
  3. 修正异步任务的创建方式
    原代码中Task.Factory.StartNew(async () => { ... })会返回嵌套的Task<Task>,直接await会导致外层任务提前完成,内部异步操作脱离管控。直接去掉不必要的任务包装即可,因为Hub方法本身就是异步方法,SignalR会在后台线程处理调用。

修改后的Hub方法完整代码:

public async Task MachineOperationOnServer(int machineID, CancellationToken cancellationToken)
{
    int progressPer = 0;

    for (int i = 1; i < 20; i++)
    {
        // 主动检查取消令牌,若已取消则抛出异常终止任务
        cancellationToken.ThrowIfCancellationRequested();

        progressPer = Convert.ToInt32(((decimal)i / 20) * 100);
        // 向客户端发送进度时也传入取消令牌,确保发送操作可被取消
        await Clients.Client(Context.ConnectionId).SendAsync("ProgressOnClient", progressPer, cancellationToken);
        
        // 使用支持取消的Task.Delay替代同步阻塞的Thread.Sleep
        await Task.Delay(1000, cancellationToken);
    }
}

关键说明

  • Blazor端调用SendAsync时传入的取消令牌,会自动传递给Hub方法的CancellationToken参数,无需额外处理。
  • 当调用tokensource.Cancel()时,取消令牌会触发ThrowIfCancellationRequested()或Task.Delay抛出OperationCanceledException,从而立即终止循环和整个任务。
  • 不需要额外创建嵌套异步任务,Hub方法本身的异步逻辑会被SignalR正确调度。

内容的提问来源于stack exchange,提问作者Ovais

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 21:15:05