.NET调用REST服务并发请求触发CancellationTokenSource已释放异常求解
问题原因
你遇到的异常核心是绑定请求的CancellationToken对应的CancellationTokenSource被提前释放,加上HttpClient的错误用法放大了并发场景下的问题:
- 本地环境网络延迟低、请求处理快,所有请求能在CancellationTokenSource释放前完成,所以不会报错;部署环境网络波动大、请求处理耗时更长,第二个请求还在执行时对应的CancellationTokenSource已经被释放,就触发了
ObjectDisposedException。 - 你每次请求都新建
HttpClient实例的写法是经典错误,该类设计为可复用实例,频繁创建会导致套接字资源耗尽、大量TIME_WAIT连接残留,高并发下会触发各类资源释放相关的异常。
解决方案
1. 修正CancellationTokenSource的生命周期
确保所有绑定了对应令牌的异步任务全部执行完成后,再释放CancellationTokenSource。最常见的错误写法是在using块内启动并发任务后,没有等待所有任务完成就退出了using作用域,导致CancellationTokenSource被提前释放:
// 错误示例 using var cts = new CancellationTokenSource(); // 直接弃元任务,没有等待执行完成 _ = CreateEmployeeRequestAsync(req1, cts.Token); _ = CreateEmployeeRequestAsync(req2, cts.Token); // 退出using作用域后cts直接被释放,后台还在运行的请求就会抛出异常
修正为等待所有并发任务完成再退出作用域:
// 正确示例 using var cts = new CancellationTokenSource(); var task1 = CreateEmployeeRequestAsync(req1, cts.Token); var task2 = CreateEmployeeRequestAsync(req2, cts.Token); // 等待所有任务执行完成后再释放cts await Task.WhenAll(task1, task2);
2. 修复HttpClient的使用方式
禁止每次请求新建HttpClient实例,改为复用单例实例,或使用IHttpClientFactory创建实例:
// 静态单例复用示例(适用于非ASP.NET Core场景) private static readonly HttpClient _sharedHttpClient = new HttpClient { BaseAddress = m_baseAddress }; // 静态构造函数初始化配置,只执行一次 static 你的类名() { var headers = _sharedHttpClient.DefaultRequestHeaders; headers.Accept.Clear(); headers.Accept.Add(new MediaTypeWithQualityHeaderValue(MEDIA_TYPE_JSON)); // 非必要不要开启ConnectionClose,复用连接性能更高 // headers.ConnectionClose = true; } [NotNull] private HttpClient GetHttpClient() { return _sharedHttpClient; }
如果是ASP.NET Core项目,直接注入IHttpClientFactory调用CreateClient方法获取实例即可,框架会自动处理连接复用和资源释放逻辑。
3. 可选优化
移除PostAsync方法内每次新建Logger实例的逻辑,复用全局Logger实例,减少不必要的资源开销。
内容的提问来源于stack exchange,提问作者Anthony14
相关产品推荐
相关产品推荐

