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

使用CsvHelper在API控制器返回CSV时遇流已释放异常求助

解决ASP.NET Core导出CSV时的System.ObjectDisposedException错误

问题背景

  • 预期目标:在API控制器中将Item对象列表导出为CSV文件
  • 实现思路:定义Item类并构造测试列表,使用CsvHelper库结合MemoryStream生成CSV,通过FileResult返回文件
  • 遇到的错误:运行时抛出System.ObjectDisposedException: Cannot access a closed Stream.,即使给StreamWriter设置了leaveOpen:true仍未解决

错误代码

using Microsoft.AspNetCore.Mvc;
using System.Globalization;
using CsvHelper;

namespace WebAPIExample2.Controllers
{
    [Route("api/[controller]")]
    [ApiController]

    public class ExportProducts : ControllerBase
    {
        public class Item
        {
            public string Name { get; set; }
            public string Description { get; set; }
        }

        [HttpGet]
        public IActionResult GetProd()
        {
            List<Item> item = new List<Item>()
            {
                new Item { Name = "John", Description = "Brown" },
                new Item { Name = "John", Description = "Brown" }
            };

            // 创建存储CSV数据的内存流
            using (var memoryStream = new MemoryStream())
            using (var writer = new StreamWriter(memoryStream, leaveOpen:true))
            using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
            { 
                csv.WriteRecords(item);
                writer.Flush();
                memoryStream.Position = 0; // 将流位置重置到起始处

                // 返回CSV文件
                return File(memoryStream, "text/csv", "exported_items.csv");
            }
        }
    }
}

解决方案

移除memoryStream的using包裹,修改后的代码如下:

using Microsoft.AspNetCore.Mvc;
using System.Globalization;
using CsvHelper;

namespace WebAPIExample2.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class ExportProducts : ControllerBase
    {
        public class Item
        {
            public string Name { get; set; }
            public string Description { get; set; }
        }

        [HttpGet]
        public IActionResult GetProd()
        {
            var items = new List<Item>()
            {
                new Item { Name = "John", Description = "Brown" },
                new Item { Name = "John", Description = "Brown" }
            };

            var memoryStream = new MemoryStream();
            using (var writer = new StreamWriter(memoryStream, leaveOpen: true))
            using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
            {
                csv.WriteRecords(items);
                writer.Flush();
                memoryStream.Position = 0;
            }

            return File(memoryStream, "text/csv", "exported_items.csv");
        }
    }
}

原因分析

  • 原代码中memoryStream被using块包裹,当执行到return语句后,using块会自动调用memoryStream.Dispose()关闭流。而ASP.NET Core的FileResult是异步处理响应的,当它尝试读取流内容时,流已经被关闭,因此抛出异常。
  • 给StreamWriter设置leaveOpen:true仅能保证StreamWriter在Dispose时不关闭底层的memoryStream,但外层memoryStream的using块依然会在结束时关闭它,这才是问题的核心。
  • ASP.NET Core的FileResult在完成响应输出后,会自动负责释放流资源,因此无需手动用using包裹memoryStream。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 17:02:43