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

如何为Controller添加CancellationToken以取消重复请求?

解决「新请求发起时取消旧请求」的CancellationToken实现方案

先明确两个核心问题:

  1. 控制器中CancellationToken的来源:
    在ASP.NET Core里,只要你在控制器Action方法中声明CancellationToken参数,框架会自动注入这个token——它默认绑定的是客户端请求断开的信号(比如用户关闭页面、主动中断请求),但这没法直接实现「新请求取消旧请求」的需求,得额外做自定义逻辑。

  2. 实现「新请求取消旧请求」的具体逻辑:
    需要自己维护一个「请求标识-取消源」的映射,每次新请求进来时,先取消同标识的旧请求,再创建新的取消源绑定到当前请求。

完整代码示例

1. 控制器层实现

用线程安全的ConcurrentDictionary存储每个查询对应的取消源,避免多请求并发冲突:

using System.Collections.Concurrent;
using System.Threading;

[ApiController]
[Route("[controller]")]
public class UserController : ControllerBase
{
    private readonly IUserService _userService;
    // 以查询字符串为key,存储对应请求的取消源
    private static readonly ConcurrentDictionary<string, CancellationTokenSource> _queryTokenSources = new();

    public UserController(IUserService userService)
    {
        _userService = userService;
    }

    [HttpGet("getUsers")]
    public async Task<IEnumerable<string>> GetUsersAsync(string query)
    {
        // 1. 取消当前查询的旧请求
        if (_queryTokenSources.TryRemove(query, out var oldTokenSource))
        {
            oldTokenSource.Cancel();
            oldTokenSource.Dispose();
        }

        // 2. 创建新的取消源,同时绑定框架自带的客户端断开token
        using var newTokenSource = CancellationTokenSource.CreateLinkedTokenSource(HttpContext.RequestAborted);
        _queryTokenSources.TryAdd(query, newTokenSource);

        try
        {
            // 3. 将自定义取消token传入服务层
            return await _userService.GetUsersAsync(query, newTokenSource.Token);
        }
        catch (OperationCanceledException)
        {
            // 可在此处理取消后的逻辑,比如返回空集合或提示信息
            return Enumerable.Empty<string>();
        }
        finally
        {
            // 4. 请求结束后清理当前取消源,防止内存泄漏
            _queryTokenSources.TryRemove(query, out _);
            newTokenSource.Dispose();
        }
    }
}

2. 服务层适配

确保服务方法支持接收CancellationToken,并在内部异步操作中传入该token:

public class UserService : IUserService
{
    public async Task<IEnumerable<string>> GetUsersAsync(string query, CancellationToken cancellationToken)
    {
        // 示例:模拟耗时异步操作,实际业务中要把token传给底层操作(如EF Core查询、Http请求等)
        await Task.Delay(3000, cancellationToken);
        
        // 实际业务逻辑示例:
        // return await _dbContext.Users.Where(u => u.Name.Contains(query)).ToListAsync(cancellationToken);
        
        return new List<string> { "用户1", "用户2", "用户3" };
    }
}

关键细节说明

  • 线程安全:必须用ConcurrentDictionary管理取消源,避免多请求并发操作时出现线程冲突。
  • 双重取消触发:通过CreateLinkedTokenSource把框架的HttpContext.RequestAborted(客户端断开的token)和自定义token绑定,这样不管是新请求触发取消,还是客户端主动断开,都会终止当前操作。
  • 内存泄漏预防:请求结束后从字典移除取消源并调用Dispose;也可以添加定时任务,清理超时未处理的取消源。
  • 用户级取消扩展:如果需要按用户区分(仅取消当前用户的旧请求),可以把字典的key改成$"{userId}_{query}",userId从User.Claims中获取。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 13:35:22