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

ASP.NET网站中CancellationToken取消长任务失效问题求助

问题:ASP.NET Web Forms中async/await配合CancellationToken无法实时取消任务

我在ASP.NET网站应用里尝试用async/await结合CancellationToken实现长任务取消,但点击「Cancel」按钮后,取消事件要等长任务执行完毕才触发,完全达不到实时取消的预期效果。

场景包含两个按钮:

  • btnStart:启动长时任务
  • btnCancel:触发任务取消

我的代码如下:

Private Const TokenKey As String = "MyOperationToken"

Protected Async Sub btnStart_Click(sender As Object, e As EventArgs) Handles btnStart.Click
        ' Create and store the cancellation token source in Session
        Dim cts As New CancellationTokenSource()
        Session(TokenKey) = cts

        Try
            lblResult.Text = "Operation started..."
            Dim result As String = Await SimulateLongOperationAsync(cts.Token)
            lblResult.Text = "Completed: " & result
        Catch ex As OperationCanceledException
            lblResult.Text = "Operation was cancelled."
        Catch ex As Exception
            lblResult.Text = "Error: " & ex.Message
        Finally
            Session.Remove(TokenKey)
        End Try
End Sub

Protected Sub btnCancel_Click(sender As Object, e As EventArgs) Handles btnCancel.Click
        ' Retrieve and cancel the token source if it exists
        Dim cts As CancellationTokenSource = TryCast(Session(TokenKey), CancellationTokenSource)
        If cts IsNot Nothing Then
            cts.Cancel()
            lblResult.Text = "Cancellation requested."
        Else
            lblResult.Text = "No operation to cancel."
        End If
End Sub

Private Async Function SimulateLongOperationAsync(token As CancellationToken) As Task(Of String)
        ' Simulate 10 seconds of work
        For i As Integer = 1 To 10
            token.ThrowIfCancellationRequested()
            Await Task.Delay(1000, token)
        Next
        Return "Success after 10 seconds"
End Function

调试时发现,点击「Start」后长任务运行,此时点击「Cancel」,btnCancel_Click的代码要等长任务结束才会执行,请问问题出在哪?


解答

核心问题是ASP.NET Web Forms的Session独占锁机制:当btnStart_Click中读写Session时,ASP.NET会对当前用户的Session加独占锁,且该锁会持有到整个请求处理完成(包括Await之后的代码执行完毕)。后续btnCancel_Click请求因为要访问同一个Session,会被强制阻塞,直到第一个请求释放Session锁,这就导致取消操作无法实时触发。

解决方法:替换Session存储方式

将CancellationTokenSource从Session转移到HttpRuntime.Cache中,避免后续请求因访问Session被阻塞。修改后的代码如下:

Private Function GetTokenCacheKey() As String
    ' 用SessionID作为缓存键,确保每个用户的任务独立
    Return $"MyOperationToken_{Session.SessionID}"
End Function

Protected Async Sub btnStart_Click(sender As Object, e As EventArgs) Handles btnStart.Click
    Dim cts As New CancellationTokenSource()
    ' 将CancellationTokenSource存入Cache,设置10分钟过期避免内存泄漏
    HttpRuntime.Cache.Insert(GetTokenCacheKey(), cts, Nothing, DateTime.Now.AddMinutes(10), TimeSpan.Zero)

    Try
        lblResult.Text = "Operation started..."
        Dim result As String = Await SimulateLongOperationAsync(cts.Token)
        lblResult.Text = "Completed: " & result
    Catch ex As OperationCanceledException
        lblResult.Text = "Operation was cancelled."
    Catch ex As Exception
        lblResult.Text = "Error: " & ex.Message
    Finally
        ' 任务结束后移除缓存
        HttpRuntime.Cache.Remove(GetTokenCacheKey())
    End Try
End Sub

Protected Sub btnCancel_Click(sender As Object, e As EventArgs) Handles btnCancel.Click
    ' 从Cache获取CancellationTokenSource
    Dim cts As CancellationTokenSource = TryCast(HttpRuntime.Cache.Get(GetTokenCacheKey()), CancellationTokenSource)
    If cts IsNot Nothing Then
        cts.Cancel()
        lblResult.Text = "Cancellation requested."
    Else
        lblResult.Text = "No operation to cancel."
    End If
End Sub

Private Async Function SimulateLongOperationAsync(token As CancellationToken) As Task(Of String)
    ' Simulate 10 seconds of work
    For i As Integer = 1 To 10
        token.ThrowIfCancellationRequested()
        Await Task.Delay(1000, token)
    Next
    Return "Success after 10 seconds"
End Function

额外说明

  • 单服务器场景下,HttpRuntime.Cache足够满足需求;如果是多服务器集群环境,可改用分布式缓存(如Redis)来跨节点共享CancellationTokenSource的引用。
  • 给缓存设置合理的过期时间,防止因任务异常结束导致内存泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 05:54:59