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

单元测试中Task.WhenAll()异步代码抛出ObjectDisposedException问题

解决异步MVC .NET Core单元测试中的ObjectDisposedException问题

这个问题我之前也碰到过,结合你描述的"单一异步任务正常、并行调用就报错"的情况,核心原因大概率是同步阻塞调用异步方法(用.Result)+ 并行任务执行导致的资源释放异常,我们一步步来解决:

1. 把单元测试改成异步模式(最关键的一步)

你的单元测试用.Result同步获取异步方法结果的写法,在并行执行异步任务时很容易触发问题——.Result会阻塞主线程,而异步任务的执行上下文和主线程产生冲突后,会导致StreamContent这类资源被提前释放。

直接把单元测试改成异步版本就能解决大部分问题:

[TestMethod]
public async Task CanGetFoos() {
    // ... 你的测试初始化代码
    var result = await service.GetFoos();
    Assert.AreEqual(2, result.Count());
}

异步测试会让任务在正确的上下文里执行,避免阻塞导致的资源异常。

2. 确认GetFooById的资源释放逻辑(无问题但需验证)

看你的GetFooById代码,using块包裹response且在释放前已经await了ReadAsStringAsync()——这部分是正确的:ReadAsStringAsync()会把流内容全部读取到内存,之后再释放response和StreamContent是安全的。而且你反序列化用的是已读取的字符串,完全不依赖原流资源,这一步逻辑没问题。

3. 若使用模拟HttpClient,确保每个请求的Content是独立实例

如果你在测试中用Moq等工具模拟HttpClient,要注意每个模拟响应都要创建独立的HttpContent实例,不能复用同一个对象。比如之前如果是这样写的:

var mockContent = new StringContent("{...}");
// 错误:所有请求复用同一个Content实例
mockHttpClient.Setup(c => c.GetAsync(It.IsAny<string>()))
              .ReturnsAsync(new HttpResponseMessage { Content = mockContent });

多个并行请求会共享同一个Content,当其中一个请求释放它后,其他请求再访问就会抛出ObjectDisposedException。正确的写法是每次返回新实例:

mockHttpClient.Setup(c => c.GetAsync(It.IsAny<string>()))
              .ReturnsAsync(() => new HttpResponseMessage { 
                  Content = new StringContent("{...}") 
              });

总结一下:优先把单元测试改成异步模式,这是解决这类问题的根本;如果是模拟HttpClient的问题,确保每个响应的Content都是独立的新实例。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:19:55