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

.NET Core 3 Web API过滤器OnActionExecuting方法读取请求体时遇已释放对象错误求助

解决.NET Core 3 Web API过滤器中读取请求体时的"Cannot access a disposed object"错误

这个问题我之前也踩过坑,核心原因是你处理请求流的方式导致底层缓冲流被意外释放,同时错误还原了原始不可重读的流,让后续MVC框架无法正常读取请求体。

错误原因分析

当你调用request.EnableBuffering()时,ASP.NET Core会把原始的HttpRequest.Body(通常是不可重读的HttpRequestStream)替换为FileBufferingReadStream——这是一个支持多次读取的缓冲流。但你的代码里用了using (StreamReader reader = new StreamReader(request.Body)),using块执行完毕后会自动释放底层的request.Body流(也就是那个缓冲流)。之后你在finally块把request.Body设回initialBody,但原始流本身不支持重置和重复读取,框架后续尝试读取请求体时,要么访问到已释放的缓冲流,要么拿到一个已经被消费过的原始流,最终抛出"Cannot access a disposed object"错误。

修正后的解决方案

只需要调整两个关键细节:不让StreamReader释放底层流,读完后重置流的位置到开头,这样后续中间件和Action就能正常读取请求体了。

public override void OnActionExecuting(ActionExecutingContext context)
{
    string body = ReadBodyAsString(context.HttpContext.Request);
    // 在这里处理读取到的请求体内容
}

private string ReadBodyAsString(HttpRequest request)
{
    // 启用缓冲,将请求流转换为可重读的缓冲流
    request.EnableBuffering();
    
    try
    {
        // 关键:设置leaveOpen: true,让StreamReader释放时不关闭底层的请求流
        using (StreamReader reader = new StreamReader(request.Body, leaveOpen: true))
        {
            string text = reader.ReadToEnd();
            // 重置流的位置到开头,确保后续环节能重新读取
            request.Body.Position = 0;
            return text;
        }
    }
    catch (Exception ex)
    {
        // 根据你的业务需求处理异常,比如日志记录
        return string.Empty;
    }
}

额外注意事项

  • 不需要再保存和还原initialBody,EnableBuffering()创建的缓冲流已经封装了原始流,并且支持重复读取。
  • 如果你的API需要处理大请求体,FileBufferingReadStream会自动将超过内存阈值的部分写入磁盘(默认阈值是30MB),这是框架的默认行为,无需额外配置。
  • 确保你的过滤器在Startup.cs/Program.cs中正确注册(比如全局过滤器,或者通过[ServiceFilter]/[TypeFilter]标记在控制器/Action上)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 08:57:37