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

ASP.NET Core后台服务读取Request.Body流出现ObjectDisposedException异常

问题原因
  • ASP.NET Core 中 Request.Body 流的生命周期与当前 HTTP 请求上下文完全绑定,当 Controller 的 Post 方法执行完成返回 Accepted 响应后,框架会自动销毁整个请求上下文,关联的 Request.Body 流也会被同步释放。
  • 后台服务为异步队列消费,消费时机晚于接口响应返回,此时流已经被释放,读取操作自然会触发 System.ObjectDisposedException 异常。
解决方案

核心逻辑为:不要直接将 Request.Body 流存入队列,在请求未结束的 Controller 执行阶段,提前将流中内容完整读取后,把读取结果存入队列即可。

步骤1:修改队列存储类型

将BackgroundJobs中队列的存储类型从Stream调整为实际的内容类型(字符串/字节数组,根据业务需求选择即可):

public class BackgroundJobs
{
    // 示例为存储序列化后的Body字符串,也可按需替换为byte[]
    public ConcurrentQueue<string> Queue { get; set; } = new ConcurrentQueue<string>();
}

步骤2:调整Controller入队逻辑

在Post方法中提前读取Request.Body的内容后再入队,注意将方法改为异步签名:

[HttpPost]
public async Task<ActionResult<string>> Post([FromQuery] string validationToken = null)
{
    if (!string.IsNullOrEmpty(validationToken))
    {
        return Ok(validationToken);
    }
    else
    {
        // 读取请求Body内容
        using var streamReader = new StreamReader(Request.Body);
        string bodyContent = await streamReader.ReadToEndAsync();
        backgroundJobs.Queue.Enqueue(bodyContent);

        return Accepted();
    }
}

如果你的业务中后续还有其他逻辑需要读取Request.Body,请在读取前调用Request.EnableBuffering(),读取完成后将Request.Body.Position重置为0即可。

步骤3:调整后台服务消费逻辑

直接从队列中获取预读取的内容处理即可,不需要再读流:

if (this.backgroundJobs.Queue.TryDequeue(out string content))
{
    var list = JsonConvert.DeserializeObject<Notifications>(content);
    // 后续业务逻辑
}

如果请求Body体积普遍较大,为避免内存占用过高,也可选择将Body写入临时文件,将临时文件路径存入队列,消费完成后删除文件即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 05:06:04